0
# Utilities and Helpers
1
2
Utility functions provide essential support for cryptographic operations including random number generation, data conversion, memory operations, and various helper functions for working with cryptographic data.
3
4
## Random Number Generation
5
6
Cryptographically secure random number generation for keys, nonces, and other security-critical values.
7
8
### Random Bytes
9
10
```javascript { .api }
11
/**
12
* Generate cryptographically secure random bytes
13
* @param length - Number of bytes to generate
14
* @returns Uint8Array - Random bytes
15
*/
16
function randombytes_buf(length: number): Uint8Array;
17
18
/**
19
* Fill existing buffer with random bytes
20
* @param buffer - Buffer to fill with random data
21
*/
22
function randombytes_buf_into(buffer: Uint8Array): void;
23
24
/**
25
* Generate deterministic random bytes from seed
26
* @param length - Number of bytes to generate
27
* @param seed - 32-byte seed for deterministic generation
28
* @returns Uint8Array - Deterministic random bytes
29
*/
30
function randombytes_buf_deterministic(
31
length: number,
32
seed: Uint8Array
33
): Uint8Array;
34
```
35
36
### Random Numbers
37
38
```javascript { .api }
39
/**
40
* Generate random 32-bit unsigned integer
41
* @returns number - Random 32-bit value
42
*/
43
function randombytes_random(): number;
44
45
/**
46
* Generate random integer in range [0, upper_bound)
47
* @param upper_bound - Exclusive upper bound (must be > 0)
48
* @returns number - Random integer in range
49
*/
50
function randombytes_uniform(upper_bound: number): number;
51
```
52
53
### Random Number System Control
54
55
```javascript { .api }
56
/**
57
* Stir the random number generator
58
*/
59
function randombytes_stir(): void;
60
61
/**
62
* Close the random number generator
63
*/
64
function randombytes_close(): void;
65
66
/**
67
* Set random number generator implementation
68
* @param implementation - Custom RNG implementation
69
*/
70
function randombytes_set_implementation(implementation: any): void;
71
```
72
73
## Data Conversion
74
75
Functions for converting between different data representations commonly used in cryptographic operations.
76
77
### String Conversion
78
79
```javascript { .api }
80
/**
81
* Convert UTF-8 string to Uint8Array
82
* @param string - UTF-8 string to convert
83
* @returns Uint8Array - String as bytes
84
*/
85
function from_string(string: string): Uint8Array;
86
87
/**
88
* Convert Uint8Array to UTF-8 string
89
* @param input - Bytes to convert to string
90
* @returns string - UTF-8 string
91
*/
92
function to_string(input: Uint8Array): string;
93
```
94
95
### Hexadecimal Conversion
96
97
```javascript { .api }
98
/**
99
* Convert hexadecimal string to Uint8Array
100
* @param hex_string - Hex string to convert (case insensitive)
101
* @returns Uint8Array - Decoded bytes
102
*/
103
function from_hex(hex_string: string): Uint8Array;
104
105
/**
106
* Convert Uint8Array to hexadecimal string
107
* @param input - Bytes to convert to hex
108
* @returns string - Lowercase hex string
109
*/
110
function to_hex(input: Uint8Array): string;
111
```
112
113
### Base64 Conversion
114
115
```javascript { .api }
116
/**
117
* Convert Base64 string to Uint8Array
118
* @param input - Base64 string to decode
119
* @param variant - Base64 variant (optional)
120
* @returns Uint8Array - Decoded bytes
121
*/
122
function from_base64(input: string, variant?: number): Uint8Array;
123
124
/**
125
* Convert Uint8Array to Base64 string
126
* @param input - Bytes to encode
127
* @param variant - Base64 variant (optional)
128
* @returns string - Base64 encoded string
129
*/
130
function to_base64(input: Uint8Array, variant?: number): string;
131
```
132
133
### Base64 Variants
134
135
```javascript { .api }
136
const base64_variants = {
137
ORIGINAL: 1, // Standard Base64 with padding
138
ORIGINAL_NO_PADDING: 3,// Standard Base64 without padding
139
URLSAFE: 5, // URL-safe Base64 with padding
140
URLSAFE_NO_PADDING: 7 // URL-safe Base64 without padding (default)
141
};
142
```
143
144
## Memory Operations
145
146
Constant-time memory operations for secure comparison and manipulation.
147
148
### Memory Comparison
149
150
```javascript { .api }
151
/**
152
* Constant-time equality comparison
153
* @param a - First buffer
154
* @param b - Second buffer
155
* @returns boolean - True if buffers are equal
156
*/
157
function memcmp(a: Uint8Array, b: Uint8Array): boolean;
158
159
/**
160
* Constant-time comparison returning -1, 0, or 1
161
* @param a - First buffer
162
* @param b - Second buffer
163
* @returns number - Comparison result (-1, 0, or 1)
164
*/
165
function compare(a: Uint8Array, b: Uint8Array): number;
166
167
/**
168
* Check if buffer contains only zeros (constant-time)
169
* @param buffer - Buffer to check
170
* @returns boolean - True if buffer is all zeros
171
*/
172
function is_zero(buffer: Uint8Array): boolean;
173
```
174
175
### Memory Manipulation
176
177
```javascript { .api }
178
/**
179
* Securely zero out memory
180
* @param buffer - Buffer to zero out
181
*/
182
function memzero(buffer: Uint8Array): void;
183
184
/**
185
* Increment little-endian number in buffer
186
* @param buffer - Buffer containing little-endian number
187
*/
188
function increment(buffer: Uint8Array): void;
189
190
/**
191
* Add two little-endian numbers
192
* @param a - First operand (modified in place)
193
* @param b - Second operand
194
*/
195
function add(a: Uint8Array, b: Uint8Array): void;
196
```
197
198
### Data Padding
199
200
```javascript { .api }
201
/**
202
* Pad buffer to specified block size using PKCS#7
203
* @param buffer - Buffer to pad
204
* @param blocksize - Target block size
205
* @returns Uint8Array - Padded buffer
206
*/
207
function pad(buffer: Uint8Array, blocksize: number): Uint8Array;
208
209
/**
210
* Remove PKCS#7 padding from buffer
211
* @param buffer - Padded buffer
212
* @param blocksize - Block size used for padding
213
* @returns Uint8Array - Unpadded buffer
214
*/
215
function unpad(buffer: Uint8Array, blocksize: number): Uint8Array;
216
```
217
218
## Verification Functions
219
220
Constant-time verification functions for various data sizes.
221
222
```javascript { .api }
223
/**
224
* Verify 16-byte values (constant-time)
225
* @param a - First 16-byte value
226
* @param b - Second 16-byte value
227
* @returns boolean - True if values are equal
228
*/
229
// Uses crypto_verify_16_BYTES constant (16)
230
231
/**
232
* Verify 32-byte values (constant-time)
233
* @param a - First 32-byte value
234
* @param b - Second 32-byte value
235
* @returns boolean - True if values are equal
236
*/
237
// Uses crypto_verify_32_BYTES constant (32)
238
239
/**
240
* Verify 64-byte values (constant-time)
241
* @param a - First 64-byte value
242
* @param b - Second 64-byte value
243
* @returns boolean - True if values are equal
244
*/
245
// Uses crypto_verify_64_BYTES constant (64)
246
```
247
248
### Verification Constants
249
250
```javascript { .api }
251
const crypto_verify_16_BYTES: number; // 16
252
const crypto_verify_32_BYTES: number; // 32
253
const crypto_verify_64_BYTES: number; // 64
254
```
255
256
## One-Time Authentication
257
258
Fast polynomial authentication using Poly1305.
259
260
### Key Generation
261
262
```javascript { .api }
263
/**
264
* Generate key for one-time authentication
265
* @returns Uint8Array - 32-byte authentication key
266
*/
267
function crypto_onetimeauth_keygen(): Uint8Array;
268
```
269
270
### Authentication
271
272
```javascript { .api }
273
/**
274
* Compute one-time authentication tag
275
* @param message - Data to authenticate
276
* @param key - 32-byte authentication key (use only once!)
277
* @returns Uint8Array - 16-byte authentication tag
278
*/
279
function crypto_onetimeauth(
280
message: Uint8Array,
281
key: Uint8Array
282
): Uint8Array;
283
284
/**
285
* Verify one-time authentication tag
286
* @param hash - Authentication tag to verify
287
* @param message - Original message
288
* @param key - 32-byte authentication key
289
* @returns boolean - True if tag is valid
290
*/
291
function crypto_onetimeauth_verify(
292
hash: Uint8Array,
293
message: Uint8Array,
294
key: Uint8Array
295
): boolean;
296
```
297
298
### Streaming One-Time Auth
299
300
```javascript { .api }
301
/**
302
* Initialize one-time auth streaming
303
* @param key - Authentication key
304
* @returns Uint8Array - State for streaming
305
*/
306
function crypto_onetimeauth_init(key: Uint8Array): Uint8Array;
307
308
/**
309
* Update streaming one-time auth
310
* @param state_address - State from init
311
* @param message_chunk - Data chunk to authenticate
312
*/
313
function crypto_onetimeauth_update(
314
state_address: any,
315
message_chunk: Uint8Array
316
): void;
317
318
/**
319
* Finalize streaming one-time auth
320
* @param state_address - State from init/update
321
* @returns Uint8Array - Authentication tag
322
*/
323
function crypto_onetimeauth_final(state_address: any): Uint8Array;
324
```
325
326
### One-Time Auth Constants
327
328
```javascript { .api }
329
const crypto_onetimeauth_BYTES: number; // 16 (tag length)
330
const crypto_onetimeauth_KEYBYTES: number; // 32 (key length)
331
332
// Poly1305 specific constants
333
const crypto_onetimeauth_poly1305_BYTES: number; // 16
334
const crypto_onetimeauth_poly1305_KEYBYTES: number; // 32
335
```
336
337
## Short Hash
338
339
Fast non-cryptographic hashing for hash tables and checksums.
340
341
### Key Generation
342
343
```javascript { .api }
344
/**
345
* Generate key for short hash function
346
* @returns Uint8Array - 16-byte hash key
347
*/
348
function crypto_shorthash_keygen(): Uint8Array;
349
```
350
351
### Hashing
352
353
```javascript { .api }
354
/**
355
* Compute short hash (SipHash-2-4)
356
* @param message - Data to hash
357
* @param key - 16-byte hash key
358
* @returns Uint8Array - 8-byte hash value
359
*/
360
function crypto_shorthash(
361
message: Uint8Array,
362
key: Uint8Array
363
): Uint8Array;
364
365
/**
366
* Compute SipHashX-2-4 (16-byte output)
367
* @param message - Data to hash
368
* @param key - 16-byte hash key
369
* @returns Uint8Array - 16-byte hash value
370
*/
371
function crypto_shorthash_siphashx24(
372
message: Uint8Array,
373
key: Uint8Array
374
): Uint8Array;
375
```
376
377
### Short Hash Constants
378
379
```javascript { .api }
380
const crypto_shorthash_BYTES: number; // 8 (SipHash-2-4 output)
381
const crypto_shorthash_KEYBYTES: number; // 16 (key length)
382
383
// SipHash-2-4 constants
384
const crypto_shorthash_siphash24_BYTES: number; // 8
385
const crypto_shorthash_siphash24_KEYBYTES: number; // 16
386
387
// SipHashX-2-4 constants
388
const crypto_shorthash_siphashx24_BYTES: number; // 16
389
const crypto_shorthash_siphashx24_KEYBYTES: number; // 16
390
```
391
392
## Library Information
393
394
Functions to get library version and information.
395
396
```javascript { .api }
397
/**
398
* Get sodium library version string
399
* @returns string - Version information
400
*/
401
function sodium_version_string(): string;
402
```
403
404
## Usage Examples
405
406
### Random Number Generation
407
408
```javascript
409
import _sodium from 'libsodium-wrappers-sumo';
410
await _sodium.ready;
411
const sodium = _sodium;
412
413
// Generate random bytes
414
const randomBytes = sodium.randombytes_buf(32);
415
console.log('Random bytes:', sodium.to_hex(randomBytes));
416
417
// Generate random numbers
418
const randomInt = sodium.randombytes_random();
419
const randomRange = sodium.randombytes_uniform(100); // 0-99
420
421
console.log('Random 32-bit int:', randomInt);
422
console.log('Random 0-99:', randomRange);
423
424
// Deterministic random generation
425
const seed = sodium.randombytes_buf(32);
426
const deterministicBytes1 = sodium.randombytes_buf_deterministic(16, seed);
427
const deterministicBytes2 = sodium.randombytes_buf_deterministic(16, seed);
428
429
console.log('Deterministic bytes match:',
430
sodium.memcmp(deterministicBytes1, deterministicBytes2)); // true
431
432
// Fill existing buffer
433
const buffer = new Uint8Array(10);
434
sodium.randombytes_buf_into(buffer);
435
console.log('Filled buffer:', sodium.to_hex(buffer));
436
```
437
438
### Data Conversion
439
440
```javascript
441
// String conversion
442
const message = 'Hello, 世界! 🌍';
443
const messageBytes = sodium.from_string(message);
444
const backToString = sodium.to_string(messageBytes);
445
446
console.log('Original:', message);
447
console.log('Bytes:', sodium.to_hex(messageBytes));
448
console.log('Back to string:', backToString);
449
console.log('Strings match:', message === backToString); // true
450
451
// Hex conversion
452
const hexString = 'deadbeef';
453
const hexBytes = sodium.from_hex(hexString);
454
const backToHex = sodium.to_hex(hexBytes);
455
456
console.log('Hex string:', hexString);
457
console.log('Hex bytes:', hexBytes);
458
console.log('Back to hex:', backToHex);
459
460
// Base64 conversion with variants
461
const data = sodium.randombytes_buf(20);
462
const base64Original = sodium.to_base64(data, sodium.base64_variants.ORIGINAL);
463
const base64UrlSafe = sodium.to_base64(data, sodium.base64_variants.URLSAFE_NO_PADDING);
464
465
console.log('Original Base64:', base64Original);
466
console.log('URL-safe Base64:', base64UrlSafe);
467
468
// Decode back
469
const decodedOriginal = sodium.from_base64(base64Original, sodium.base64_variants.ORIGINAL);
470
const decodedUrlSafe = sodium.from_base64(base64UrlSafe, sodium.base64_variants.URLSAFE_NO_PADDING);
471
472
console.log('Decoded match:', sodium.memcmp(data, decodedOriginal)); // true
473
console.log('URL-safe decoded match:', sodium.memcmp(data, decodedUrlSafe)); // true
474
```
475
476
### Memory Operations
477
478
```javascript
479
// Constant-time comparison
480
const secret1 = sodium.randombytes_buf(16);
481
const secret2 = sodium.randombytes_buf(16);
482
const secret1Copy = new Uint8Array(secret1);
483
484
console.log('Secrets equal:', sodium.memcmp(secret1, secret2)); // false
485
console.log('Secret equals copy:', sodium.memcmp(secret1, secret1Copy)); // true
486
487
// Comparison with ordering
488
const a = sodium.from_hex('0102');
489
const b = sodium.from_hex('0201');
490
const comparison = sodium.compare(a, b);
491
492
console.log('Comparison result:', comparison); // -1 (a < b)
493
494
// Zero checking
495
const zeros = new Uint8Array(16); // All zeros
496
const nonZeros = sodium.randombytes_buf(16);
497
498
console.log('Zeros detected:', sodium.is_zero(zeros)); // true
499
console.log('Non-zeros detected:', !sodium.is_zero(nonZeros)); // true
500
501
// Memory zeroing
502
const sensitive = sodium.from_string('sensitive data');
503
console.log('Before zeroing:', sodium.to_string(sensitive));
504
sodium.memzero(sensitive);
505
console.log('After zeroing is all zeros:', sodium.is_zero(sensitive)); // true
506
507
// Increment operation (little-endian)
508
const counter = new Uint8Array([0, 0, 0, 1]); // 16777216 in little-endian
509
console.log('Counter before:', Array.from(counter));
510
sodium.increment(counter);
511
console.log('Counter after:', Array.from(counter)); // [1, 0, 0, 1]
512
513
// Addition (little-endian)
514
const num1 = new Uint8Array([5, 0, 0, 0]); // 5
515
const num2 = new Uint8Array([3, 0, 0, 0]); // 3
516
sodium.add(num1, num2); // num1 = num1 + num2
517
console.log('Addition result:', Array.from(num1)); // [8, 0, 0, 0] = 8
518
```
519
520
### Padding Operations
521
522
```javascript
523
// PKCS#7 padding
524
const data = sodium.from_string('Hello World!');
525
const padded = sodium.pad(data, 16);
526
527
console.log('Original length:', data.length); // 12
528
console.log('Padded length:', padded.length); // 16
529
console.log('Padded data:', sodium.to_hex(padded));
530
531
// Unpadding
532
const unpadded = sodium.unpad(padded, 16);
533
console.log('Unpadded matches original:',
534
sodium.memcmp(data, unpadded)); // true
535
536
// Different block sizes
537
const padded8 = sodium.pad(data, 8);
538
const padded32 = sodium.pad(data, 32);
539
540
console.log('8-byte padded length:', padded8.length); // 16
541
console.log('32-byte padded length:', padded32.length); // 32
542
```
543
544
### One-Time Authentication
545
546
```javascript
547
// One-time authentication (use key only once!)
548
const onetimeKey = sodium.crypto_onetimeauth_keygen();
549
const message = sodium.from_string('One-time authenticated message');
550
551
const tag = sodium.crypto_onetimeauth(message, onetimeKey);
552
const isValid = sodium.crypto_onetimeauth_verify(tag, message, onetimeKey);
553
554
console.log('One-time auth tag:', sodium.to_hex(tag));
555
console.log('Tag is valid:', isValid); // true
556
557
// CRITICAL: Never reuse the key!
558
// Using the same key again breaks security
559
sodium.memzero(onetimeKey); // Clear the key
560
561
// Streaming one-time authentication
562
const streamKey = sodium.crypto_onetimeauth_keygen();
563
const state = sodium.crypto_onetimeauth_init(streamKey);
564
565
const chunk1 = sodium.from_string('First chunk ');
566
const chunk2 = sodium.from_string('Second chunk');
567
568
sodium.crypto_onetimeauth_update(state, chunk1);
569
sodium.crypto_onetimeauth_update(state, chunk2);
570
571
const streamTag = sodium.crypto_onetimeauth_final(state);
572
573
// Verify against complete message
574
const completeMessage = sodium.from_string('First chunk Second chunk');
575
const streamValid = sodium.crypto_onetimeauth_verify(streamTag, completeMessage, streamKey);
576
577
console.log('Streaming auth valid:', streamValid); // true
578
sodium.memzero(streamKey); // Clear the key
579
```
580
581
### Short Hash for Hash Tables
582
583
```javascript
584
// Fast non-cryptographic hashing
585
const hashKey = sodium.crypto_shorthash_keygen();
586
587
// Hash table simulation
588
const hashTable = new Map();
589
590
function addToHashTable(key, value) {
591
const keyBytes = sodium.from_string(key);
592
const hash = sodium.crypto_shorthash(keyBytes, hashKey);
593
const hashHex = sodium.to_hex(hash);
594
595
if (!hashTable.has(hashHex)) {
596
hashTable.set(hashHex, []);
597
}
598
hashTable.get(hashHex).push({ key, value });
599
}
600
601
function getFromHashTable(key) {
602
const keyBytes = sodium.from_string(key);
603
const hash = sodium.crypto_shorthash(keyBytes, hashKey);
604
const hashHex = sodium.to_hex(hash);
605
606
const bucket = hashTable.get(hashHex);
607
if (!bucket) return undefined;
608
609
const entry = bucket.find(item => item.key === key);
610
return entry ? entry.value : undefined;
611
}
612
613
// Add some entries
614
addToHashTable('alice', { id: 1, name: 'Alice' });
615
addToHashTable('bob', { id: 2, name: 'Bob' });
616
addToHashTable('charlie', { id: 3, name: 'Charlie' });
617
618
// Retrieve entries
619
console.log('Alice:', getFromHashTable('alice'));
620
console.log('Bob:', getFromHashTable('bob'));
621
console.log('David:', getFromHashTable('david')); // undefined
622
623
// Show hash distribution
624
console.log('Hash table size:', hashTable.size);
625
console.log('Hash table contents:');
626
for (const [hash, bucket] of hashTable) {
627
console.log(` ${hash}: ${bucket.length} entries`);
628
}
629
630
// Extended hash for better distribution
631
const extendedHash = sodium.crypto_shorthash_siphashx24(
632
sodium.from_string('test key'), hashKey
633
);
634
console.log('Extended hash:', sodium.to_hex(extendedHash)); // 16 bytes
635
```
636
637
### Utility Helper Class
638
639
```javascript
640
class CryptoUtils {
641
static generateId(length = 16) {
642
const bytes = sodium.randombytes_buf(length);
643
return sodium.to_hex(bytes);
644
}
645
646
static constantTimeEquals(a, b) {
647
if (a.length !== b.length) return false;
648
return sodium.memcmp(a, b);
649
}
650
651
static secureRandom(min, max) {
652
const range = max - min;
653
if (range <= 0) throw new Error('Invalid range');
654
return min + sodium.randombytes_uniform(range);
655
}
656
657
static encodeData(data, format = 'base64') {
658
switch (format) {
659
case 'hex': return sodium.to_hex(data);
660
case 'base64': return sodium.to_base64(data);
661
case 'base64url': return sodium.to_base64(data, sodium.base64_variants.URLSAFE_NO_PADDING);
662
default: throw new Error('Unsupported format');
663
}
664
}
665
666
static decodeData(encoded, format = 'base64') {
667
switch (format) {
668
case 'hex': return sodium.from_hex(encoded);
669
case 'base64': return sodium.from_base64(encoded);
670
case 'base64url': return sodium.from_base64(encoded, sodium.base64_variants.URLSAFE_NO_PADDING);
671
default: throw new Error('Unsupported format');
672
}
673
}
674
675
static clearSensitiveData(...buffers) {
676
for (const buffer of buffers) {
677
if (buffer instanceof Uint8Array) {
678
sodium.memzero(buffer);
679
}
680
}
681
}
682
683
static createChecksum(data) {
684
// Fast non-cryptographic checksum
685
const key = sodium.crypto_shorthash_keygen();
686
const checksum = sodium.crypto_shorthash(data, key);
687
return {
688
checksum: sodium.to_hex(checksum),
689
key: sodium.to_hex(key)
690
};
691
}
692
693
static verifyChecksum(data, checksumHex, keyHex) {
694
const key = sodium.from_hex(keyHex);
695
const expectedChecksum = sodium.crypto_shorthash(data, key);
696
const actualChecksum = sodium.from_hex(checksumHex);
697
return sodium.memcmp(expectedChecksum, actualChecksum);
698
}
699
}
700
701
// Usage examples
702
console.log('Random ID:', CryptoUtils.generateId());
703
console.log('Random number 1-100:', CryptoUtils.secureRandom(1, 101));
704
705
const testData = sodium.from_string('Test data');
706
const hex = CryptoUtils.encodeData(testData, 'hex');
707
const base64 = CryptoUtils.encodeData(testData, 'base64');
708
const base64url = CryptoUtils.encodeData(testData, 'base64url');
709
710
console.log('Hex:', hex);
711
console.log('Base64:', base64);
712
console.log('Base64URL:', base64url);
713
714
// Checksum example
715
const fileData = sodium.from_string('Important file content');
716
const { checksum, key } = CryptoUtils.createChecksum(fileData);
717
const isValid = CryptoUtils.verifyChecksum(fileData, checksum, key);
718
719
console.log('Checksum valid:', isValid); // true
720
```
721
722
### Library Information
723
724
```javascript
725
// Get library version
726
console.log('Sodium version:', sodium.sodium_version_string());
727
console.log('Library version major:', sodium.SODIUM_LIBRARY_VERSION_MAJOR);
728
console.log('Library version minor:', sodium.SODIUM_LIBRARY_VERSION_MINOR);
729
console.log('Version string constant:', sodium.SODIUM_VERSION_STRING);
730
```
731
732
## Security Considerations
733
734
- **Random Number Quality**: All random functions use cryptographically secure generators
735
- **Constant-Time Operations**: Memory comparison functions prevent timing attacks
736
- **Memory Security**: Use memzero() to clear sensitive data from memory
737
- **One-Time Keys**: Never reuse keys for one-time authentication
738
- **Deterministic Generation**: Use only for testing, not production secrets
739
- **Data Validation**: Always validate decoded data before use
740
741
## Performance Notes
742
743
- **Short Hash**: Fast for hash tables but not cryptographically secure
744
- **Memory Operations**: Constant-time operations may be slower than naive implementations
745
- **Base64 Variants**: Choose appropriate variant for your use case
746
- **Random Generation**: Generating large amounts of random data may be slow
747
748
Utility functions form the foundation for secure cryptographic implementations and should be used consistently throughout applications.