The 'TypePKI' library is an opensource free TypeScript PKI library which is the successor of the long lived jsrsasign library.
The 'typepki-webcrypto' is W3C Web Crypto API [1][2] helper function sub module for TypePKI library.
The signHex function can sign a data with RSA, RSA-PSS and ECDSA algorithms very easily.
Here is an example to sign a string "apple りんご":
const pemPrivateKey = `-----BEGIN PRIVATE KEY-----
MI...
-----END PRIVATE KEY-----`;
(async () = {
const privateKey = await importPEM(pemPrivateKey, "SHA256withRSA");
const hexSignatureValue = await signHex("SHA256withRSA", privateKey, utf8tohex("apple りんご"));
})();
The typepki-strconv provides many functions convert any data to a hexadecimal string such as ArrayBuffer, Base64, Base64URL or raw string.
The verifyHex function can verify a RSA, RSA-PSS and ECDSA signature very easily too.
Here is an example to verify a RSA signature for a string "apple りんご":
const pemPublicKey = `-----BEGIN PUBLIC KEY-----
MI...
-----END PRIVATE KEY-----`;
const hexSignature = "12ab...";
(async () = {
const publicKey = await importPEM(pemPublicKey, "SHA256withRSA");
const isValid = await verifyHex("SHA256withRSA", publicKey, hexSignature, utf8tohex("apple りんご"));
})();
ECDSA signature value has two types of encoding:
Here is a ASN.1 dump of OpenSSL or Java's ECDSA signature value which consists R and S integer value:
SEQUENCE {
INTEGER
28 AE 0E 46 36 FE 21 53 1B 05 AC BF 66 D1 C5 91
9A D8 69 29 78 52 D7 2F F2 F4 A1 06 0F 2D 56 32
INTEGER
00 C2 C8 75 D9 60 0C DC 56 FB 43 39 DB 1E 00 FF
64 2D ED A5 44 21 88 D3 3F 68 1D A6 E4 38 F4 4E
EA
}
Note that its S value starts 0x00 because ASN.1 Integer value uses two's complement encoding and positive integer's first byte is bigger than 0x7f, 0x00 will be added.
ASN.1 encoded value will be following in hexadecimal:
3045
0220
28ae0e4636fe21531b05acbf66d1c5919ad869297852d72ff2f4a1060f2d5632
0221
00c2c875d9600cdc56fb4339db1e00ff642deda5442188d33f681da6e438f44eea
The "typepki-webcrypto", JWS or W3C Web Crypto API will use R and S concatinated signature value. For W3C Web Crypto API, above signature will be encoded as following:
28ae0e4636fe21531b05acbf66d1c5919ad869297852d72ff2f4a1060f2d5632
c2c875d9600cdc56fb4339db1e00ff642deda5442188d33f681da6e438f44eea
Note that there is no 0x00 in front of S's value.
So when you need to exchange signatures among W3C Web Crypto API and OpenSSL, you need to convert ECDSA signature value. In such case, "typepki-webcrypto" provides converter functions:
W3C Web Crypto API requires an explict salt length for RSA-PSS signature. It means there is no default value. So the "typepki-webcrypt" functions use the default salt length value as the same as W3C Web Crypto API. Their values are the same as using hash algorithm byte length.
OpenSSL pkeyutl
command can be specified rsa_pss_saltlen
option for signing and verifying RSA-PSS signature.
Here is a summary for salt length:
SHA1+PSS | SHA256+PSS | SHA384+PSS | SHA512+PSS | |
---|---|---|---|---|
saltlen in W3C Crypto | need explicit | need explicit | need explicit | need explicit |
typepki default | 20 | 32 | 48 | 64 |
OpenSSL saltlen=digest(default) | 20 | 32 | 48 | 64 |
OpenSSL RSA key byte len + saltlen=max | keylen-22 | keylen-34 | keylen-50 | keylen-66 |
OpenSSL RSA2048 saltlen=max | 234 | 222 | 206 | 190 |
JWA/JWS | - | 32 | 48 | 64 |
For OpenSSL's rsa_pss_saltlen:max
, its salt value will be calculated as follows:
saltlen = key_byte_length - hash_byte_length - 2
For example of RSA 2048bit, RSA-PSS, hash=SHA1(20bytes), mgf=SHA1 and saltlen=max, then:
saltlen = 256 - 20 - 2 = 234
Thus, when you want to verify a signature generated by OpenSSL with RSA-PSS and saltlen=max, you need to explictly specify salt length with the number.