# HTTP 客户端 Crypto API 参考

> For the complete documentation index, see [llms.txt](https://www.jetbrains.com.cn/help/idea/llms.txt).

`crypto`  对象提供对 HTTP 客户端加密 API 的访问权限，该 API 支持加密哈希函数、HMAC、RSA 和 ECDSA，用于生成 HTTP 签名。 该功能可通过便捷方法（  `crypto.hmac` ，哈希算法）以及  `crypto.subtle`  接口的实现获得。

> **Note:**
> 在 HTTP 客户端中，所有  `crypto.subtle`  操作都是同步的，并直接返回结果。

HTTP 客户端还支持 JWT 操作，使用  `jwt.*`  函数可在预请求脚本中直接生成、检查并验证 JSON Web Token。

## 哈希方法

|  方法  |  参数  |  描述  |
| --- | --- | --- |
|   `updateWithText`   |      `textInput` （字符串）        `编码` （字符串）：  `textInput`  的编码。 默认值为  `UTF8` 。     |  将字符串更新为哈希值。  |
|   `updateWithHex`   |      `hexInput` （字符串）     |  将十六进制字符串更新为哈希值。  |
|   `updateWithBase64`   |      `base64Input` （字符串）        `urlSafe` （布尔值）：如果字符串使用 Base64 的 URL 安全变体进行编码，请输入  `true` 。     |  将一个 Base64 字符串更新为哈希。  |
|   `digest().toHex()`   |  —  |  生成哈希并将其转换为十六进制格式。  |
|   `digest().toBase64()`   |   `urlSafe` （布尔）：如果您想使用 URL 安全的 Base64 变体，请输入  `true`   |  生成哈希，并将其转换为 Base64 格式。  |

## HMAC 方法

`crypto.hmac`  对象使您能够使用 HMAC 对 HTTP 请求进行签名。 它可以访问所有 [hash 方法](#hash_methods)来生成哈希，并且还有方法可以获取令牌的秘密部分。

|  方法  |  参数  |  描述  |
| --- | --- | --- |
|   `withTextSecret`   |      `textSecret` （字符串）        `编码` （字符串）：  `textSecret`  的编码。 默认值为  `UTF8` 。     |  将用于 HMAC 的密钥放入。  |
|   `withHexSecret`   |      `hexSecret` （字符串）     |  将密钥置于十六进制格式。  |
|   `withBase64Secret`   |      `base64Input` （字符串）        `urlSafe` （布尔值）：如果字符串使用 Base64 的 URL 安全变体进行编码，请输入  `true` 。     |  将密钥置于 Base64 格式。  |

HTTP 客户端支持使用 SHA-2 和 SHA-3 算法系列的 HMAC。 要使用 SHA-2 算法，您可以调用专用方法，例如  `crypto.hmac.sha256()`  或  `crypto.hmac.sha512()` 。 对于 SHA-3 算法，格式有所不同，您需要使用带有位长度参数的单个方法，例如  `crypto.hmac.sha3('512')`  或  `crypto.hmac.sha3('256')` 。

示例：

基于 SHA-2 的 HMAC:

```JAVASCRIPT
< {%
    const signature = crypto.hmac.sha256()
        .withTextSecret(request.environment.get("secret")) // get variable from http-client.private.env.json
        .updateWithText(request.body.tryGetSubstituted())
        .digest().toHex();
    request.variables.set("signature", signature)

    const hash = crypto.sha256()
        .updateWithText(request.body.tryGetSubstituted())
        .digest().toHex();
    request.variables.set("hash", hash)
%}
POST https://httpbin.org/post
    X-My-Signature: {{signature}}
    X-My-Hash: {{hash}}
    Content-Type: application/json

{
    "prop": "value"
}
                
```

基于 SHA-3 的 HMAC:

```JAVASCRIPT
< {%
    const signature = crypto.hmac.sha3('512')
            .withTextSecret('Secret')
            .updateWithText('Servus!')
            .digest().toHex();
    console.log(`signature: ${signature}`)
%}
POST https://examples.http-client.intellij.net/anything
                    
```

## RSA 方法

`crypto.subtle`  接口使您能够在预请求脚本中使用 RSA 加密。 HTTP 客户端支持 [Web Crypto API](https://w3c.github.io/webcrypto/#algorithms)，它提供密钥生成、加密、解密、数字签名、签名验证等标准加密功能。

|  方法  |  参数  |  描述  |  算法  |
| --- | --- | --- | --- |
|   `encrypt`   |      `algorithm` （对象）：指定加密算法及其参数。 具体的对象结构取决于所使用的算法。        `key` （对象）：指定包含用于加密的密钥的  `CryptoKey` 。        `data`  (  `TypedArray` )     |  使用指定的算法和密钥对提供的数据进行加密。  |  RSA-OAEP  |
|   `decrypt`   |      `algorithm` （对象）：指定解密算法及其参数。 具体的对象结构取决于所使用的算法。        `key` （对象）：指定包含用于解密的密钥的  `CryptoKey` 。        `data`  (  `TypedArray` )     |  使用指定的算法和密钥对加密的数据进行解密。  |  RSA-OAEP  |
|   `sign`   |      `algorithm` （对象）：指定用于生成数字签名的算法。 具体的对象结构取决于所使用的算法。        `key` （对象）：指定包含用于签名的密钥的  `CryptoKey` 。 如果  `algorithm`  标识的是公钥密码系统，则该密钥为私钥。        `data`  (  `TypedArray` )     |  使用指定的算法和密钥生成数字签名。  |  RSASSA-PKCS1-v1_5, RSA-PSS  |
|   `verify`   |      `algorithm` （对象）：指定用于签名验证的算法。 具体的对象结构取决于所使用的算法。        `key` （对象）：指定包含用于验证签名的密钥的  `CryptoKey` 。 对称算法使用密钥，公钥算法使用公钥。        `signature`  (  `TypedArray` )        `data`  (  `TypedArray` )     |  使用指定的算法和密钥验证数字签名。  |  RSASSA-PKCS1-v1_5, RSA-PSS  |
|   `generateKey`   |      `algorithm` （对象）：指定用于定义要生成的密钥类型的算法。        `extractable` （布尔值）：输入  `true`  以允许使用  `crypto.subtle.exportKey()`  或  `crypto.subtle.wrapKey()`  导出密钥。        `keyUsages` （字符串数组）：指定可对密钥执行的操作列表。     |  生成新密钥（用于对称算法）或密钥对（用于公钥算法）。  |  RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP  |
|   `importKey`   |      `format` （字符串）：指定要导入的密钥的数据格式。 可能的取值：  `pkcs8` 、  `spki` 。        `keyData`  (  `TypedArray` )        `algorithm` （对象）：指定定义要导入的密钥类型的算法，并提供特定于该算法的参数。        `extractable` （布尔值）：输入  `true`  以允许使用  `crypto.subtle.exportKey()`  或  `crypto.subtle.wrapKey()`  导出密钥。        `keyUsages` （字符串数组）：指定可对密钥执行的操作列表。     |  以外部可移植格式导入密钥，并返回一个  `CryptoKey`  对象。  |  RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP  |
|   `exportKey`   |      `format` （字符串）：指定导出该密钥的数据格式。 可能的取值：  `pkcs8` 、  `spki` 。        `key` （对象）：指定要导出的  `CryptoKey` 。     |  导出一个  `CryptoKey` ，并以外部可移植格式返回密钥。  |  RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP  |

示例：

```JAVASCRIPT
< {%
    const keyPair = crypto.subtle.generateKey({
                name: "RSA-PSS",
                modulusLength: 2048,
                publicExponent: new Uint8Array([1, 0, 1]),
                hash: "SHA-256"
            },
            true,
            ["sign", "verify"])
    const text = "Hello, HTTP Client Pre Script!!!";
    const data = string2byteArray(text);
    const signature = crypto.subtle.sign(
            {
                name: "RSA-PSS",
            },
            keyPair.privateKey,
            data
    );
    const verified = crypto.subtle.verify(
            {
                name: "RSA-PSS",
            },
            keyPair.publicKey,
            signature,
            data);

    client.log(`${text}, verified: ${verified}`);
%}

GET https://example.com/api/path

```

## ECDSA 方法

HTTP 客户端通过 [Web Crypto API](https://w3c.github.io/webcrypto/#algorithms) 支持 ECDSA，该 API 提供  `SubtleCrypto`  接口（  `crypto.subtle` ）。 您可以生成或导入密钥，然后在预请求脚本中对数据进行签名和验证。

|  方法  |  参数  |  描述  |
| --- | --- | --- |
|   `sign`   |      `algorithm` ：指定签名算法，例如  `{ name: "ECDSA", hash: "SHA-256" }` 。        `key` （对象）：提供具有  `"sign"`  用途的私有  `CryptoKey` 。        `data` ：以  `ArrayBuffer`  或  `TypedArray`  的形式提供要签名的数据。     |  使用 ECDSA 私钥对给定数据创建数字签名。  |
|   `verify`   |      `algorithm` （对象）：指定用于签名验证的算法。 具体的对象结构取决于所使用的算法。        `key` （对象）：提供具有  `"verify"`  用途的公有  `CryptoKey` 。        `signature`  (  `ArrayBuffer` )        `data`  (  `ArrayBuffer` )     |  验证给定签名对于所提供数据和 ECDSA 公钥是否有效。  |
|   `generateKey`   |      `algorithm` （对象）：指定算法和曲线，例如  `{ name: "ECDSA", namedCurve: "P-256" }` 。        `extractable` （布尔）：输入  `true`  以允许使用  `crypto.subtle.exportKey()`  导出密钥。        `keyUsages` （字符串数组）：指定该密钥可能的操作列表，例如  `["sign", "verify"]` 。     |  为指定曲线生成新的椭圆曲线密钥对。 返回带有  `{ publicKey, privateKey }`  的对象。  |
|   `importKey`   |      `format` （字符串）：指定要导入的密钥的数据格式。 可能的取值：  `pkcs8` 、  `spki` 。        `keyData` （  `ArrayBuffer` 、  `TypedArray` 、  `DataView` ，或  `JSONWebKey` ）        `algorithm` （对象）：指定算法和曲线，例如  `{ name: "ECDSA", namedCurve: "P-256" }` 。        `extractable` （布尔）：输入  `true`  以允许使用  `crypto.subtle.exportKey()`  导出密钥。        `keyUsages` （字符串数组）：指定这些密钥可能的操作列表。     |  导入现有的椭圆曲线密钥并返回一个  `CryptoKey` 。 支持的格式取决于该密钥是公钥还是私钥。  |
|   `exportKey`   |      `format` （字符串）：指定导出该密钥的数据格式。 可能的取值：  `pkcs8` 、  `spki` 。        `key` （对象）：指定要导出的  `CryptoKey` 。     |  以指定格式导出给定的 ECDSA 密钥。 对于 PKCS8/SPKI/RAW，返回二进制数据（  `ArrayBuffer` ）；对于 JWK，返回 JSON 对象。  |

示例：

```JAVASCRIPT
< {%
const base64publicKey = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEn8E8vCgnmyDISke4RQVt0uwhE0AFL61crfJ7gmKkLgISv+eV5zAB1GBVQ/mj/4bZO8yJnFCrNGILHN59aCEEfA=='
const base64privateKey = 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgXMpTO9h9dsmz9f9XfpvdUbU8PGt7ZMiN95Irv0XAgQyhRANCAASfwTy8KCebIMhKR7hFBW3S7CETQAUvrVyt8nuCYqQuAhK/55XnMAHUYFVD+aP/htk7zImcUKs0Ygsc3n1oIQR8'
const privateKey = crypto.subtle.importKey(
        'pkcs8',
        Uint8Array.from(atob(base64privateKey), c => c.codePointAt(0)),
        { name: "ECDSA", namedCurve: "P-256" },
        true,
        ["sign"]
)

const msg = "Hello from HTTP Client!"
const signature = crypto.subtle.sign(
        { name: "ECDSA", hash: "SHA-256" },
        privateKey,
        Uint8Array.from(msg, c => c.charCodeAt(0))
)

const publicKey = crypto.subtle.importKey(
        'spki',
        Uint8Array.from(atob(base64publicKey), c => c.codePointAt(0)),
        { name: "ECDSA", namedCurve: "P-256" },
        true,
        ["verify"]
)
const verificationResult = crypto.subtle.verify(
        { name: "ECDSA", hash: "SHA-256" },
        publicKey,
        signature,
        Uint8Array.from(msg, c => c.charCodeAt(0))
)
console.log(`verificationResult: ${verificationResult}`)
%}
GET https://example.com/api/path


```

## JWT 签名

HTTP 客户端的预请求脚本支持创建并签名 [JSON Web Token (JWT)](https://datatracker.ietf.org/doc/html/rfc7519)。 JWT 由三部分组成：base64url 编码的标头、base64url 编码的负载（声明）以及加密签名。

`jwt.*`  函数使您能够在请求中直接生成、检查并验证令牌。 已签名的 JWT 可以存储在预请求变量中（例如  `jwt_token` ），随后用于对请求进行身份验证。

对于 JWT 签名，HTTP 客户端支持与常用库（例如 [node/jsonwebtoken](https://github.com/auth0/node-jsonwebtoken/blob/master/README.md)）相同的算法，包括：

* HS256 / HS384 / HS512 — 使用 SHA-256/SHA-384/SHA-512 的 HMAC

* RS256/RS384/RS512 — 使用 SHA-256/SHA-384/SHA-512 的 RSASSA-PKCS1-v1_5

* PS256/PS384/PS512 — 使用 SHA-256/SHA-384/SHA-512 的 RSA-PSS

* ES256/ES384/ES512 — 使用 SHA-256/SHA-384/SHA-512 的 ECDSA

|  方法  |  参数  |  描述  |
| --- | --- | --- |
|   `jwt.sign`   |      `payload` ：指定一个对象字面量、缓冲区或表示有效 JSON 的字符串。        `key` ：对于 HMAC，指定密钥字符串或字节；对于 RSA 或 ECDSA，指定私钥（  `CryptoKey`  / PEM）。        `options` ：指定一个对象，其中包含  `algorithm` （HS256、RS256、PS256、ES256、ES384 等）以及标准声明（例如  `issuer` 、  `受众` ）。     |  创建并签名 JWT。  |
|   `jwt.verify`   |      `令牌` ：指定要验证的 JWT 字符串。        `key` ：指定用于 RSA/ECDSA 的密钥 (HMAC) 或公钥 (  `CryptoKey`  / PEM)。        `options` ：指定一个对象，其中包含  `algorithm` （HS256、RS256、PS256、ES256、ES384 等）以及标准声明（例如  `issuer` 、  `受众` ）。     |  验证 JWT 的签名，并可选择强制检查声明。  |
|   `jwt.decode`   |      `令牌` ：指定要解码的 JWT 字符串。     |  在不验证签名的情况下解码 JWT（用于检查或调试）。  |

以下 RSA-PSS 签名示例演示了：

* 生成 RSA 密钥对

* 使用 RSA-PSS 对任意消息进行签名和验证

* 使用 PS256 创建并验证 JWT

* 将公钥导出为 PEM（ `spki` ），以便外部工具进行验证

```JAVASCRIPT
            
< {%
    let algorithm = {
        name: 'RSA-PSS',
        modulusLength: 2048,                       // 2048 or 4096 bits recommended
        publicExponent: new Uint8Array([1, 0, 1]), // 65537 (standard exponent)
        hash: "SHA-256"
    };
    const pair = crypto.subtle.generateKey(algorithm,
            true,
            ['sign', 'verify']);

    let otherClaim = 'Servus, HTTP Client Pre Script!!!';

    const rsaSignature = crypto.subtle.sign({
                name: "RSA-PSS",
                saltLength: 32
            },
            pair.privateKey,
            Uint8Array.from(otherClaim, c => c.charCodeAt(0)))

    console.log(`verify ${otherClaim}: ${crypto.subtle.verify({name: "RSA-PSS", saltLength: 32}, pair.publicKey, rsaSignature, Uint8Array.from(otherClaim, c => c.charCodeAt(0)))}`);


    const rsaJwt = jwt.sign({
        other_claim: otherClaim,
    }, pair.privateKey, {
        algorithm: 'PS256'
    })


    console.log(`RSA JWT: ${rsaJwt}`)

    console.log(`RSA verification: ${jwt.verify(rsaJwt, pair.publicKey, {algorithm: 'PS256'})}`)

    let publicKey = btoa(String.fromCharCode(...new Uint8Array(crypto.subtle.exportKey("spki", pair.publicKey))));
    console.log(`public key: \n-----BEGIN PUBLIC KEY-----\n${publicKey.match(/.{1,64}/g).join('\n')}\n-----END PUBLIC KEY-----`)


%}
GET examples.http-client.intellij.net/path
    
        
```

下一个示例演示如何使用 HS256 算法（基于 SHA-256 的 HMAC）生成、解码和验证 JWT。 该令牌包含  `aud` （audience）声明，会在验证期间进行校验。

```JAVASCRIPT
            
< {%
    const signature = jwt.sign({
        other_claim: "some value",
        aud:['jetbrains']
    }, client.variables.file.get('secret'))

    console.log(`signature: ${jwt.decode(signature).payload.aud}`)


    client.variables.global.set("jwt_token", signature)
    console.log(jwt.verify(signature, client.variables.file.get('secret'), {
        audience: 'jetbrains',
        algorithm: 'HS256'
    }))
    console.log(signature)
%}

GET examples.http-client.intellij.net/path
            
        
```

