@omnituum/pqc-shared 0.2.6
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/LICENSE +22 -0
- package/README.md +543 -0
- package/dist/crypto/index.cjs +807 -0
- package/dist/crypto/index.d.cts +641 -0
- package/dist/crypto/index.d.ts +641 -0
- package/dist/crypto/index.js +716 -0
- package/dist/decrypt-eSHlbh1j.d.cts +321 -0
- package/dist/decrypt-eSHlbh1j.d.ts +321 -0
- package/dist/fs/index.cjs +1168 -0
- package/dist/fs/index.d.cts +400 -0
- package/dist/fs/index.d.ts +400 -0
- package/dist/fs/index.js +1091 -0
- package/dist/index.cjs +2160 -0
- package/dist/index.d.cts +282 -0
- package/dist/index.d.ts +282 -0
- package/dist/index.js +2031 -0
- package/dist/integrity-CCYjrap3.d.ts +31 -0
- package/dist/integrity-Dx9jukMH.d.cts +31 -0
- package/dist/types-61c7Q9ri.d.ts +134 -0
- package/dist/types-Ch0y-n7K.d.cts +134 -0
- package/dist/utils/index.cjs +129 -0
- package/dist/utils/index.d.cts +49 -0
- package/dist/utils/index.d.ts +49 -0
- package/dist/utils/index.js +114 -0
- package/dist/vault/index.cjs +713 -0
- package/dist/vault/index.d.cts +237 -0
- package/dist/vault/index.d.ts +237 -0
- package/dist/vault/index.js +677 -0
- package/dist/version-BygzPVGs.d.cts +55 -0
- package/dist/version-BygzPVGs.d.ts +55 -0
- package/package.json +86 -0
- package/src/crypto/dilithium.ts +233 -0
- package/src/crypto/hybrid.ts +358 -0
- package/src/crypto/index.ts +181 -0
- package/src/crypto/kyber.ts +199 -0
- package/src/crypto/nacl.ts +204 -0
- package/src/crypto/primitives/blake3.ts +141 -0
- package/src/crypto/primitives/chacha.ts +211 -0
- package/src/crypto/primitives/hkdf.ts +192 -0
- package/src/crypto/primitives/index.ts +54 -0
- package/src/crypto/primitives.ts +144 -0
- package/src/crypto/x25519.ts +134 -0
- package/src/fs/aes.ts +343 -0
- package/src/fs/argon2.ts +184 -0
- package/src/fs/browser.ts +408 -0
- package/src/fs/decrypt.ts +320 -0
- package/src/fs/encrypt.ts +324 -0
- package/src/fs/format.ts +425 -0
- package/src/fs/index.ts +144 -0
- package/src/fs/types.ts +304 -0
- package/src/index.ts +414 -0
- package/src/kdf/index.ts +311 -0
- package/src/runtime/crypto.ts +16 -0
- package/src/security/index.ts +345 -0
- package/src/tunnel/index.ts +39 -0
- package/src/tunnel/session.ts +229 -0
- package/src/tunnel/types.ts +115 -0
- package/src/utils/entropy.ts +128 -0
- package/src/utils/index.ts +25 -0
- package/src/utils/integrity.ts +95 -0
- package/src/vault/decrypt.ts +167 -0
- package/src/vault/encrypt.ts +207 -0
- package/src/vault/index.ts +71 -0
- package/src/vault/manager.ts +327 -0
- package/src/vault/migrate.ts +190 -0
- package/src/vault/types.ts +177 -0
- package/src/version.ts +304 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum PQC Shared - ChaCha20-Poly1305 Primitives
|
|
3
|
+
*
|
|
4
|
+
* AEAD ciphers for authenticated encryption:
|
|
5
|
+
* - ChaCha20-Poly1305: Standard AEAD (12-byte nonce)
|
|
6
|
+
* - XChaCha20-Poly1305: Extended nonce variant (24-byte nonce)
|
|
7
|
+
*
|
|
8
|
+
* Used in Noise protocols and general-purpose encryption.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { chacha20poly1305, xchacha20poly1305 } from '@noble/ciphers/chacha';
|
|
12
|
+
|
|
13
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
14
|
+
// TYPES
|
|
15
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
16
|
+
|
|
17
|
+
export interface ChaChaPayload {
|
|
18
|
+
/** Nonce (12 bytes for standard, 24 bytes for xchacha) */
|
|
19
|
+
nonce: Uint8Array;
|
|
20
|
+
/** Ciphertext with Poly1305 tag (16 bytes appended) */
|
|
21
|
+
ciphertext: Uint8Array;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
// CHACHA20-POLY1305 (12-byte nonce)
|
|
26
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Encrypt using ChaCha20-Poly1305.
|
|
30
|
+
*
|
|
31
|
+
* @param key - 32-byte encryption key
|
|
32
|
+
* @param nonce - 12-byte nonce (must be unique per key)
|
|
33
|
+
* @param plaintext - Data to encrypt
|
|
34
|
+
* @param aad - Optional additional authenticated data
|
|
35
|
+
* @returns Ciphertext with Poly1305 tag appended
|
|
36
|
+
*/
|
|
37
|
+
export function chaCha20Poly1305Encrypt(
|
|
38
|
+
key: Uint8Array,
|
|
39
|
+
nonce: Uint8Array,
|
|
40
|
+
plaintext: Uint8Array,
|
|
41
|
+
aad?: Uint8Array
|
|
42
|
+
): Uint8Array {
|
|
43
|
+
if (key.length !== 32) {
|
|
44
|
+
throw new Error('ChaCha20-Poly1305 key must be 32 bytes');
|
|
45
|
+
}
|
|
46
|
+
if (nonce.length !== 12) {
|
|
47
|
+
throw new Error('ChaCha20-Poly1305 nonce must be 12 bytes');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const cipher = chacha20poly1305(key, nonce, aad);
|
|
51
|
+
return cipher.encrypt(plaintext);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Decrypt using ChaCha20-Poly1305.
|
|
56
|
+
*
|
|
57
|
+
* @param key - 32-byte encryption key
|
|
58
|
+
* @param nonce - 12-byte nonce
|
|
59
|
+
* @param ciphertext - Ciphertext with Poly1305 tag
|
|
60
|
+
* @param aad - Optional additional authenticated data
|
|
61
|
+
* @returns Plaintext, or null if authentication fails
|
|
62
|
+
*/
|
|
63
|
+
export function chaCha20Poly1305Decrypt(
|
|
64
|
+
key: Uint8Array,
|
|
65
|
+
nonce: Uint8Array,
|
|
66
|
+
ciphertext: Uint8Array,
|
|
67
|
+
aad?: Uint8Array
|
|
68
|
+
): Uint8Array | null {
|
|
69
|
+
if (key.length !== 32) {
|
|
70
|
+
throw new Error('ChaCha20-Poly1305 key must be 32 bytes');
|
|
71
|
+
}
|
|
72
|
+
if (nonce.length !== 12) {
|
|
73
|
+
throw new Error('ChaCha20-Poly1305 nonce must be 12 bytes');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const cipher = chacha20poly1305(key, nonce, aad);
|
|
78
|
+
return cipher.decrypt(ciphertext);
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
85
|
+
// XCHACHA20-POLY1305 (24-byte nonce)
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Encrypt using XChaCha20-Poly1305 (extended 24-byte nonce).
|
|
90
|
+
*
|
|
91
|
+
* XChaCha20-Poly1305 is preferred for most applications because:
|
|
92
|
+
* - 24-byte nonce can be safely generated randomly
|
|
93
|
+
* - No nonce collision risk with ~2^80 messages per key
|
|
94
|
+
*
|
|
95
|
+
* @param key - 32-byte encryption key
|
|
96
|
+
* @param nonce - 24-byte nonce (can be random)
|
|
97
|
+
* @param plaintext - Data to encrypt
|
|
98
|
+
* @param aad - Optional additional authenticated data
|
|
99
|
+
* @returns Ciphertext with Poly1305 tag appended
|
|
100
|
+
*/
|
|
101
|
+
export function xChaCha20Poly1305Encrypt(
|
|
102
|
+
key: Uint8Array,
|
|
103
|
+
nonce: Uint8Array,
|
|
104
|
+
plaintext: Uint8Array,
|
|
105
|
+
aad?: Uint8Array
|
|
106
|
+
): Uint8Array {
|
|
107
|
+
if (key.length !== 32) {
|
|
108
|
+
throw new Error('XChaCha20-Poly1305 key must be 32 bytes');
|
|
109
|
+
}
|
|
110
|
+
if (nonce.length !== 24) {
|
|
111
|
+
throw new Error('XChaCha20-Poly1305 nonce must be 24 bytes');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const cipher = xchacha20poly1305(key, nonce, aad);
|
|
115
|
+
return cipher.encrypt(plaintext);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Decrypt using XChaCha20-Poly1305.
|
|
120
|
+
*
|
|
121
|
+
* @param key - 32-byte encryption key
|
|
122
|
+
* @param nonce - 24-byte nonce
|
|
123
|
+
* @param ciphertext - Ciphertext with Poly1305 tag
|
|
124
|
+
* @param aad - Optional additional authenticated data
|
|
125
|
+
* @returns Plaintext, or null if authentication fails
|
|
126
|
+
*/
|
|
127
|
+
export function xChaCha20Poly1305Decrypt(
|
|
128
|
+
key: Uint8Array,
|
|
129
|
+
nonce: Uint8Array,
|
|
130
|
+
ciphertext: Uint8Array,
|
|
131
|
+
aad?: Uint8Array
|
|
132
|
+
): Uint8Array | null {
|
|
133
|
+
if (key.length !== 32) {
|
|
134
|
+
throw new Error('XChaCha20-Poly1305 key must be 32 bytes');
|
|
135
|
+
}
|
|
136
|
+
if (nonce.length !== 24) {
|
|
137
|
+
throw new Error('XChaCha20-Poly1305 nonce must be 24 bytes');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const cipher = xchacha20poly1305(key, nonce, aad);
|
|
142
|
+
return cipher.decrypt(ciphertext);
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
149
|
+
// FACTORY FUNCTIONS (for Noise protocol compatibility)
|
|
150
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Create an XChaCha20-Poly1305 cipher instance.
|
|
154
|
+
* Compatible with @noble/ciphers API used in noise-kyber.
|
|
155
|
+
*
|
|
156
|
+
* @param key - 32-byte encryption key
|
|
157
|
+
* @param nonce - 24-byte nonce
|
|
158
|
+
* @param aad - Optional additional authenticated data
|
|
159
|
+
* @returns Cipher with encrypt/decrypt methods
|
|
160
|
+
*/
|
|
161
|
+
export function createXChaCha20Poly1305(
|
|
162
|
+
key: Uint8Array,
|
|
163
|
+
nonce: Uint8Array,
|
|
164
|
+
aad?: Uint8Array
|
|
165
|
+
) {
|
|
166
|
+
if (key.length !== 32) {
|
|
167
|
+
throw new Error('XChaCha20-Poly1305 key must be 32 bytes');
|
|
168
|
+
}
|
|
169
|
+
if (nonce.length !== 24) {
|
|
170
|
+
throw new Error('XChaCha20-Poly1305 nonce must be 24 bytes');
|
|
171
|
+
}
|
|
172
|
+
return xchacha20poly1305(key, nonce, aad);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a ChaCha20-Poly1305 cipher instance.
|
|
177
|
+
*
|
|
178
|
+
* @param key - 32-byte encryption key
|
|
179
|
+
* @param nonce - 12-byte nonce
|
|
180
|
+
* @param aad - Optional additional authenticated data
|
|
181
|
+
* @returns Cipher with encrypt/decrypt methods
|
|
182
|
+
*/
|
|
183
|
+
export function createChaCha20Poly1305(
|
|
184
|
+
key: Uint8Array,
|
|
185
|
+
nonce: Uint8Array,
|
|
186
|
+
aad?: Uint8Array
|
|
187
|
+
) {
|
|
188
|
+
if (key.length !== 32) {
|
|
189
|
+
throw new Error('ChaCha20-Poly1305 key must be 32 bytes');
|
|
190
|
+
}
|
|
191
|
+
if (nonce.length !== 12) {
|
|
192
|
+
throw new Error('ChaCha20-Poly1305 nonce must be 12 bytes');
|
|
193
|
+
}
|
|
194
|
+
return chacha20poly1305(key, nonce, aad);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
198
|
+
// CONSTANTS
|
|
199
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
200
|
+
|
|
201
|
+
/** ChaCha20-Poly1305 key size (32 bytes) */
|
|
202
|
+
export const CHACHA20_KEY_SIZE = 32;
|
|
203
|
+
|
|
204
|
+
/** ChaCha20-Poly1305 nonce size (12 bytes) */
|
|
205
|
+
export const CHACHA20_NONCE_SIZE = 12;
|
|
206
|
+
|
|
207
|
+
/** XChaCha20-Poly1305 nonce size (24 bytes) */
|
|
208
|
+
export const XCHACHA20_NONCE_SIZE = 24;
|
|
209
|
+
|
|
210
|
+
/** Poly1305 tag size (16 bytes) */
|
|
211
|
+
export const POLY1305_TAG_SIZE = 16;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum PQC Shared - HKDF (HMAC-based Key Derivation Function)
|
|
3
|
+
*
|
|
4
|
+
* HKDF is a NIST-approved key derivation function (RFC 5869).
|
|
5
|
+
* Supports SHA-256 (default) and SHA-512 hash functions.
|
|
6
|
+
*
|
|
7
|
+
* Two-step process:
|
|
8
|
+
* 1. Extract: Derive a pseudorandom key from input keying material
|
|
9
|
+
* 2. Expand: Generate output keying material from the PRK
|
|
10
|
+
*
|
|
11
|
+
* Used in Noise protocols for key derivation.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { hkdf, extract, expand } from '@noble/hashes/hkdf';
|
|
15
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
16
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
// TYPES
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
export type HkdfHash = 'sha256' | 'sha512';
|
|
23
|
+
|
|
24
|
+
export interface HkdfOptions {
|
|
25
|
+
/** Hash function to use (default: 'sha256') */
|
|
26
|
+
hash?: HkdfHash;
|
|
27
|
+
/** Context info for domain separation */
|
|
28
|
+
info?: Uint8Array | string;
|
|
29
|
+
/** Salt (defaults to zeroes if not provided) */
|
|
30
|
+
salt?: Uint8Array;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
+
// HKDF FUNCTIONS
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Derive keys using HKDF (Extract + Expand).
|
|
39
|
+
*
|
|
40
|
+
* @param ikm - Input keying material
|
|
41
|
+
* @param outputLength - Desired output length in bytes
|
|
42
|
+
* @param options - Optional salt, info, and hash selection
|
|
43
|
+
* @returns Derived key material
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* // Basic key derivation
|
|
48
|
+
* const key = hkdfDerive(sharedSecret, 32);
|
|
49
|
+
*
|
|
50
|
+
* // With domain separation
|
|
51
|
+
* const key = hkdfDerive(sharedSecret, 32, {
|
|
52
|
+
* info: 'MyApp v1.0 encryption key'
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // With salt
|
|
56
|
+
* const key = hkdfDerive(sharedSecret, 32, {
|
|
57
|
+
* salt: randomSalt,
|
|
58
|
+
* info: 'session key'
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function hkdfDerive(
|
|
63
|
+
ikm: Uint8Array,
|
|
64
|
+
outputLength: number,
|
|
65
|
+
options?: HkdfOptions
|
|
66
|
+
): Uint8Array {
|
|
67
|
+
const hashFn = getHashFunction(options?.hash ?? 'sha256');
|
|
68
|
+
const info = normalizeInfo(options?.info);
|
|
69
|
+
const salt = options?.salt;
|
|
70
|
+
|
|
71
|
+
return hkdf(hashFn, ikm, salt, info, outputLength);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* HKDF-Extract: Derive a pseudorandom key from input keying material.
|
|
76
|
+
*
|
|
77
|
+
* @param ikm - Input keying material
|
|
78
|
+
* @param salt - Optional salt (defaults to zeroes)
|
|
79
|
+
* @param hash - Hash function ('sha256' or 'sha512')
|
|
80
|
+
* @returns Pseudorandom key (32 bytes for SHA-256, 64 for SHA-512)
|
|
81
|
+
*/
|
|
82
|
+
export function hkdfExtract(
|
|
83
|
+
ikm: Uint8Array,
|
|
84
|
+
salt?: Uint8Array,
|
|
85
|
+
hash: HkdfHash = 'sha256'
|
|
86
|
+
): Uint8Array {
|
|
87
|
+
const hashFn = getHashFunction(hash);
|
|
88
|
+
return extract(hashFn, ikm, salt);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* HKDF-Expand: Expand a pseudorandom key into output keying material.
|
|
93
|
+
*
|
|
94
|
+
* @param prk - Pseudorandom key (from hkdfExtract)
|
|
95
|
+
* @param info - Context info for domain separation
|
|
96
|
+
* @param outputLength - Desired output length in bytes
|
|
97
|
+
* @param hash - Hash function ('sha256' or 'sha512')
|
|
98
|
+
* @returns Output keying material
|
|
99
|
+
*/
|
|
100
|
+
export function hkdfExpand(
|
|
101
|
+
prk: Uint8Array,
|
|
102
|
+
info: Uint8Array | string | undefined,
|
|
103
|
+
outputLength: number,
|
|
104
|
+
hash: HkdfHash = 'sha256'
|
|
105
|
+
): Uint8Array {
|
|
106
|
+
const hashFn = getHashFunction(hash);
|
|
107
|
+
return expand(hashFn, prk, normalizeInfo(info), outputLength);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
111
|
+
// NOISE PROTOCOL HELPERS
|
|
112
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* HKDF for Noise protocol key derivation.
|
|
116
|
+
* Splits output into chaining key and output key.
|
|
117
|
+
*
|
|
118
|
+
* @param chainingKey - Current chaining key (salt)
|
|
119
|
+
* @param inputKeyMaterial - New key material to mix in
|
|
120
|
+
* @returns [newChainingKey, outputKey] - both 32 bytes
|
|
121
|
+
*/
|
|
122
|
+
export function hkdfSplitForNoise(
|
|
123
|
+
chainingKey: Uint8Array,
|
|
124
|
+
inputKeyMaterial: Uint8Array
|
|
125
|
+
): [Uint8Array, Uint8Array] {
|
|
126
|
+
const prk = hkdfExtract(inputKeyMaterial, chainingKey, 'sha256');
|
|
127
|
+
const output = hkdfExpand(prk, undefined, 64, 'sha256');
|
|
128
|
+
|
|
129
|
+
return [
|
|
130
|
+
output.slice(0, 32), // New chaining key
|
|
131
|
+
output.slice(32, 64), // Output key
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* HKDF for Noise protocol with three outputs.
|
|
137
|
+
* Used when deriving transport keys at the end of handshake.
|
|
138
|
+
*
|
|
139
|
+
* @param chainingKey - Current chaining key
|
|
140
|
+
* @param inputKeyMaterial - Key material to mix
|
|
141
|
+
* @returns [ck, k1, k2] - chaining key and two output keys
|
|
142
|
+
*/
|
|
143
|
+
export function hkdfTripleSplitForNoise(
|
|
144
|
+
chainingKey: Uint8Array,
|
|
145
|
+
inputKeyMaterial: Uint8Array
|
|
146
|
+
): [Uint8Array, Uint8Array, Uint8Array] {
|
|
147
|
+
const prk = hkdfExtract(inputKeyMaterial, chainingKey, 'sha256');
|
|
148
|
+
const output = hkdfExpand(prk, undefined, 96, 'sha256');
|
|
149
|
+
|
|
150
|
+
return [
|
|
151
|
+
output.slice(0, 32), // New chaining key
|
|
152
|
+
output.slice(32, 64), // Output key 1
|
|
153
|
+
output.slice(64, 96), // Output key 2
|
|
154
|
+
];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
158
|
+
// HELPERS
|
|
159
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
160
|
+
|
|
161
|
+
function getHashFunction(hash: HkdfHash) {
|
|
162
|
+
switch (hash) {
|
|
163
|
+
case 'sha256':
|
|
164
|
+
return sha256;
|
|
165
|
+
case 'sha512':
|
|
166
|
+
return sha512;
|
|
167
|
+
default:
|
|
168
|
+
throw new Error(`Unsupported HKDF hash: ${hash}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function normalizeInfo(info: Uint8Array | string | undefined): Uint8Array {
|
|
173
|
+
if (!info) return new Uint8Array(0);
|
|
174
|
+
if (typeof info === 'string') return new TextEncoder().encode(info);
|
|
175
|
+
return info;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
179
|
+
// CONSTANTS
|
|
180
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
181
|
+
|
|
182
|
+
/** HKDF-SHA256 output size (32 bytes) */
|
|
183
|
+
export const HKDF_SHA256_OUTPUT_SIZE = 32;
|
|
184
|
+
|
|
185
|
+
/** HKDF-SHA512 output size (64 bytes) */
|
|
186
|
+
export const HKDF_SHA512_OUTPUT_SIZE = 64;
|
|
187
|
+
|
|
188
|
+
/** Maximum HKDF output length for SHA-256 (255 * 32 = 8160 bytes) */
|
|
189
|
+
export const HKDF_SHA256_MAX_OUTPUT = 255 * 32;
|
|
190
|
+
|
|
191
|
+
/** Maximum HKDF output length for SHA-512 (255 * 64 = 16320 bytes) */
|
|
192
|
+
export const HKDF_SHA512_MAX_OUTPUT = 255 * 64;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum PQC Shared - Cryptographic Primitives
|
|
3
|
+
*
|
|
4
|
+
* Low-level cryptographic building blocks for higher-level protocols.
|
|
5
|
+
* These are exported for use in noise-kyber and other protocol implementations.
|
|
6
|
+
*
|
|
7
|
+
* PRIMITIVES (use directly):
|
|
8
|
+
* - BLAKE3: Fast hash function for transcripts
|
|
9
|
+
* - ChaCha20-Poly1305: AEAD encryption (12-byte nonce)
|
|
10
|
+
* - XChaCha20-Poly1305: AEAD encryption (24-byte nonce, safer)
|
|
11
|
+
* - HKDF: Key derivation function (NIST-approved)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// BLAKE3 hash function
|
|
15
|
+
export {
|
|
16
|
+
blake3,
|
|
17
|
+
blake3Hex,
|
|
18
|
+
blake3Mac,
|
|
19
|
+
blake3DeriveKey,
|
|
20
|
+
BLAKE3_OUTPUT_LENGTH,
|
|
21
|
+
BLAKE3_KEY_LENGTH,
|
|
22
|
+
BLAKE3_BLOCK_SIZE,
|
|
23
|
+
type Blake3Options,
|
|
24
|
+
} from './blake3';
|
|
25
|
+
|
|
26
|
+
// ChaCha20-Poly1305 AEAD
|
|
27
|
+
export {
|
|
28
|
+
chaCha20Poly1305Encrypt,
|
|
29
|
+
chaCha20Poly1305Decrypt,
|
|
30
|
+
xChaCha20Poly1305Encrypt,
|
|
31
|
+
xChaCha20Poly1305Decrypt,
|
|
32
|
+
createChaCha20Poly1305,
|
|
33
|
+
createXChaCha20Poly1305,
|
|
34
|
+
CHACHA20_KEY_SIZE,
|
|
35
|
+
CHACHA20_NONCE_SIZE,
|
|
36
|
+
XCHACHA20_NONCE_SIZE,
|
|
37
|
+
POLY1305_TAG_SIZE,
|
|
38
|
+
type ChaChaPayload,
|
|
39
|
+
} from './chacha';
|
|
40
|
+
|
|
41
|
+
// HKDF key derivation
|
|
42
|
+
export {
|
|
43
|
+
hkdfDerive,
|
|
44
|
+
hkdfExtract,
|
|
45
|
+
hkdfExpand,
|
|
46
|
+
hkdfSplitForNoise,
|
|
47
|
+
hkdfTripleSplitForNoise,
|
|
48
|
+
HKDF_SHA256_OUTPUT_SIZE,
|
|
49
|
+
HKDF_SHA512_OUTPUT_SIZE,
|
|
50
|
+
HKDF_SHA256_MAX_OUTPUT,
|
|
51
|
+
HKDF_SHA512_MAX_OUTPUT,
|
|
52
|
+
type HkdfHash,
|
|
53
|
+
type HkdfOptions,
|
|
54
|
+
} from './hkdf';
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum PQC Shared - Cryptographic Primitives
|
|
3
|
+
*
|
|
4
|
+
* Pure browser implementation - no Node.js dependencies.
|
|
5
|
+
* Uses Web Crypto API and @noble/hashes for all operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { sha256 as nobleSha256 } from '@noble/hashes/sha256';
|
|
9
|
+
import { hmac } from '@noble/hashes/hmac';
|
|
10
|
+
|
|
11
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
12
|
+
// TEXT ENCODING
|
|
13
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
14
|
+
|
|
15
|
+
export const textEncoder = new TextEncoder();
|
|
16
|
+
export const textDecoder = new TextDecoder();
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
// BASE64 UTILITIES
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
export function toB64(bytes: Uint8Array): string {
|
|
23
|
+
let binary = '';
|
|
24
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
25
|
+
binary += String.fromCharCode(bytes[i]);
|
|
26
|
+
}
|
|
27
|
+
return btoa(binary);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function fromB64(str: string): Uint8Array {
|
|
31
|
+
const binary = atob(str);
|
|
32
|
+
const bytes = new Uint8Array(binary.length);
|
|
33
|
+
for (let i = 0; i < binary.length; i++) {
|
|
34
|
+
bytes[i] = binary.charCodeAt(i);
|
|
35
|
+
}
|
|
36
|
+
return bytes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
|
+
// HEX UTILITIES
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
|
|
43
|
+
export function toHex(bytes: Uint8Array): string {
|
|
44
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function fromHex(hex: string): Uint8Array {
|
|
48
|
+
const s = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
49
|
+
const normalized = s.length % 2 ? '0' + s : s;
|
|
50
|
+
const out = new Uint8Array(normalized.length / 2);
|
|
51
|
+
for (let i = 0; i < out.length; i++) {
|
|
52
|
+
out[i] = parseInt(normalized.slice(i * 2, i * 2 + 2), 16);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
58
|
+
// VALIDATION
|
|
59
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
60
|
+
|
|
61
|
+
export function assertLen(label: string, arr: Uint8Array, n: number): void {
|
|
62
|
+
if (arr.length !== n) {
|
|
63
|
+
throw new Error(`${label} must be ${n} bytes, got ${arr.length}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
68
|
+
// RANDOMNESS (Web Crypto API)
|
|
69
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
70
|
+
|
|
71
|
+
export function rand32(): Uint8Array {
|
|
72
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(32));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function rand24(): Uint8Array {
|
|
76
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(24));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function rand12(): Uint8Array {
|
|
80
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(12));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function randN(n: number): Uint8Array {
|
|
84
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(n));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
88
|
+
// HASHING (@noble/hashes)
|
|
89
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
90
|
+
|
|
91
|
+
export function sha256(bytes: Uint8Array): Uint8Array {
|
|
92
|
+
return nobleSha256(bytes);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function sha256String(str: string): Uint8Array {
|
|
96
|
+
return sha256(textEncoder.encode(str));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
100
|
+
// KEY DERIVATION (HKDF-SHA-256)
|
|
101
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
102
|
+
|
|
103
|
+
export function hkdfSha256(
|
|
104
|
+
ikm: Uint8Array,
|
|
105
|
+
opts?: { salt?: Uint8Array; info?: Uint8Array; length?: number }
|
|
106
|
+
): Uint8Array {
|
|
107
|
+
const salt = opts?.salt ?? new Uint8Array(32);
|
|
108
|
+
const info = opts?.info ?? new Uint8Array(0);
|
|
109
|
+
const L = opts?.length ?? 32;
|
|
110
|
+
|
|
111
|
+
// Extract
|
|
112
|
+
const prk = hmac(nobleSha256, salt, ikm);
|
|
113
|
+
|
|
114
|
+
// Expand
|
|
115
|
+
let t = new Uint8Array(0);
|
|
116
|
+
const chunks: Uint8Array[] = [];
|
|
117
|
+
for (let i = 1; i <= Math.ceil(L / 32); i++) {
|
|
118
|
+
const input = new Uint8Array(t.length + info.length + 1);
|
|
119
|
+
input.set(t, 0);
|
|
120
|
+
input.set(info, t.length);
|
|
121
|
+
input[input.length - 1] = i;
|
|
122
|
+
t = new Uint8Array(hmac(nobleSha256, prk, input));
|
|
123
|
+
chunks.push(t);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const out = new Uint8Array(L);
|
|
127
|
+
let off = 0;
|
|
128
|
+
for (const c of chunks) {
|
|
129
|
+
out.set(c.subarray(0, L - off), off);
|
|
130
|
+
off += c.length;
|
|
131
|
+
if (off >= L) break;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
137
|
+
// CONVENIENCE EXPORTS
|
|
138
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
139
|
+
|
|
140
|
+
export const b64 = toB64;
|
|
141
|
+
export const ub64 = fromB64;
|
|
142
|
+
|
|
143
|
+
export const u8 = (s: string | Uint8Array) =>
|
|
144
|
+
typeof s === 'string' ? textEncoder.encode(s) : s;
|