@reallyme/crypto 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/p256Ecdsa.d.ts +10 -0
- package/dist/p256Ecdsa.js +92 -0
- package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,10 @@ const digest = ReallyMeCrypto.hash(
|
|
|
31
31
|
The API is synchronous. Signature verification throws `ReallyMeCryptoError` on
|
|
32
32
|
invalid input rather than returning a boolean that can be accidentally ignored.
|
|
33
33
|
|
|
34
|
+
`ReallyMeP256Ecdsa` normalizes canonical DER or fixed-width 64-byte `r || s`
|
|
35
|
+
signatures to low-S form for HSM and platform-keystore integrations. The helper
|
|
36
|
+
does not replace verification against the signed message.
|
|
37
|
+
|
|
34
38
|
KDF facade selectors are family-specific: `deriveKey` accepts only PBKDF2,
|
|
35
39
|
`deriveHkdf` accepts only HKDF, and the JWA Concat KDF and KMAC methods accept
|
|
36
40
|
their exact selectors. Argon2id uses the dedicated `deriveArgon2id` route with
|
package/dist/p256Ecdsa.d.ts
CHANGED
|
@@ -11,6 +11,16 @@ export declare const P256_ECDSA_DER_SIGNATURE_MAX_LENGTH = 72;
|
|
|
11
11
|
* of applying a TypeScript-only low-S normalization policy.
|
|
12
12
|
*/
|
|
13
13
|
export declare const ReallyMeP256Ecdsa: {
|
|
14
|
+
/**
|
|
15
|
+
* Returns the canonical low-S form of a canonical DER signature.
|
|
16
|
+
*
|
|
17
|
+
* This is a representation transform for signatures returned by HSMs and
|
|
18
|
+
* platform keystores. It does not verify authenticity; callers must still
|
|
19
|
+
* verify the signature against the exact message that was signed.
|
|
20
|
+
*/
|
|
21
|
+
readonly normalizeDerSignatureLowS: (signature: Uint8Array) => Uint8Array;
|
|
22
|
+
/** Returns the low-S form of an exact 64-byte JOSE `r || s` signature. */
|
|
23
|
+
readonly normalizeJoseSignatureLowS: (signature: Uint8Array) => Uint8Array;
|
|
14
24
|
readonly generateKeyPair: () => {
|
|
15
25
|
publicKey: Uint8Array;
|
|
16
26
|
secretKey: Uint8Array;
|
package/dist/p256Ecdsa.js
CHANGED
|
@@ -10,6 +10,81 @@ export const P256_ECDSA_SECRET_KEY_LENGTH = 32;
|
|
|
10
10
|
export const P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 33;
|
|
11
11
|
export const P256_ECDSA_COMPACT_SIGNATURE_LENGTH = 64;
|
|
12
12
|
export const P256_ECDSA_DER_SIGNATURE_MAX_LENGTH = 72;
|
|
13
|
+
const P256_CURVE_ORDER = Uint8Array.from([
|
|
14
|
+
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
15
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
16
|
+
0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
|
|
17
|
+
0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
|
|
18
|
+
]);
|
|
19
|
+
const P256_HALF_CURVE_ORDER = Uint8Array.from([
|
|
20
|
+
0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
|
|
21
|
+
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
22
|
+
0xde, 0x73, 0x7d, 0x56, 0xd3, 0x8b, 0xcf, 0x42,
|
|
23
|
+
0x79, 0xdc, 0xe5, 0x61, 0x7e, 0x31, 0x92, 0xa8,
|
|
24
|
+
]);
|
|
25
|
+
const compareBigEndian = (left, right) => {
|
|
26
|
+
if (left.length !== right.length) {
|
|
27
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
28
|
+
}
|
|
29
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
30
|
+
const leftByte = left[index];
|
|
31
|
+
const rightByte = right[index];
|
|
32
|
+
if (leftByte === undefined || rightByte === undefined) {
|
|
33
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
34
|
+
}
|
|
35
|
+
if (leftByte !== rightByte) {
|
|
36
|
+
return leftByte < rightByte ? -1 : 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
|
+
};
|
|
41
|
+
const isZeroScalar = (scalar) => {
|
|
42
|
+
for (const byte of scalar) {
|
|
43
|
+
if (byte !== 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
const subtractBigEndian = (left, right) => {
|
|
50
|
+
if (left.length !== right.length || compareBigEndian(left, right) < 0) {
|
|
51
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
52
|
+
}
|
|
53
|
+
const result = new Uint8Array(left.length);
|
|
54
|
+
let borrow = 0;
|
|
55
|
+
for (let index = left.length - 1; index >= 0; index -= 1) {
|
|
56
|
+
const leftByte = left[index];
|
|
57
|
+
const rightByte = right[index];
|
|
58
|
+
if (leftByte === undefined || rightByte === undefined) {
|
|
59
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
60
|
+
}
|
|
61
|
+
const difference = leftByte - rightByte - borrow;
|
|
62
|
+
result[index] = difference < 0 ? difference + 256 : difference;
|
|
63
|
+
borrow = difference < 0 ? 1 : 0;
|
|
64
|
+
}
|
|
65
|
+
if (borrow !== 0) {
|
|
66
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
const normalizeP256JoseSignatureLowS = (signature) => {
|
|
71
|
+
if (signature.length !== P256_ECDSA_COMPACT_SIGNATURE_LENGTH) {
|
|
72
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
73
|
+
}
|
|
74
|
+
const normalized = new Uint8Array(signature);
|
|
75
|
+
const r = normalized.slice(0, P256_ECDSA_SECRET_KEY_LENGTH);
|
|
76
|
+
const s = normalized.slice(P256_ECDSA_SECRET_KEY_LENGTH);
|
|
77
|
+
if (isZeroScalar(r) ||
|
|
78
|
+
isZeroScalar(s) ||
|
|
79
|
+
compareBigEndian(r, P256_CURVE_ORDER) >= 0 ||
|
|
80
|
+
compareBigEndian(s, P256_CURVE_ORDER) >= 0) {
|
|
81
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
82
|
+
}
|
|
83
|
+
if (compareBigEndian(s, P256_HALF_CURVE_ORDER) > 0) {
|
|
84
|
+
normalized.set(subtractBigEndian(P256_CURVE_ORDER, s), P256_ECDSA_SECRET_KEY_LENGTH);
|
|
85
|
+
}
|
|
86
|
+
return normalized;
|
|
87
|
+
};
|
|
13
88
|
/**
|
|
14
89
|
* P-256 ECDSA backed by @noble/curves.
|
|
15
90
|
*
|
|
@@ -19,6 +94,23 @@ export const P256_ECDSA_DER_SIGNATURE_MAX_LENGTH = 72;
|
|
|
19
94
|
* of applying a TypeScript-only low-S normalization policy.
|
|
20
95
|
*/
|
|
21
96
|
export const ReallyMeP256Ecdsa = {
|
|
97
|
+
/**
|
|
98
|
+
* Returns the canonical low-S form of a canonical DER signature.
|
|
99
|
+
*
|
|
100
|
+
* This is a representation transform for signatures returned by HSMs and
|
|
101
|
+
* platform keystores. It does not verify authenticity; callers must still
|
|
102
|
+
* verify the signature against the exact message that was signed.
|
|
103
|
+
*/
|
|
104
|
+
normalizeDerSignatureLowS(signature) {
|
|
105
|
+
ensureByteArray(signature);
|
|
106
|
+
const compact = decodeEcdsaDerSignature(signature, P256_ECDSA_SECRET_KEY_LENGTH, P256_ECDSA_DER_SIGNATURE_MAX_LENGTH);
|
|
107
|
+
return encodeEcdsaDerSignature(normalizeP256JoseSignatureLowS(compact), P256_ECDSA_SECRET_KEY_LENGTH);
|
|
108
|
+
},
|
|
109
|
+
/** Returns the low-S form of an exact 64-byte JOSE `r || s` signature. */
|
|
110
|
+
normalizeJoseSignatureLowS(signature) {
|
|
111
|
+
ensureByteArray(signature);
|
|
112
|
+
return normalizeP256JoseSignatureLowS(signature);
|
|
113
|
+
},
|
|
22
114
|
generateKeyPair() {
|
|
23
115
|
const secretKey = p256.utils.randomSecretKey();
|
|
24
116
|
return {
|
|
Binary file
|