Skip to content

Commit f3088c3

Browse files
committed
Enforce bytes type
Must be either Uint8Array or Buffer
1 parent b2b9d61 commit f3088c3

File tree

4 files changed

+31
-22
lines changed

4 files changed

+31
-22
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -198,24 +198,24 @@ We'll start with using 32 characters. What 32 characters, you ask? Well, the [Ch
198198
199199
We're using the same __bits__ calculation since we haven't changed the number of IDs or the accepted risk of probabilistic uniqueness. But this time we use 32 characters and our resulting ID only requires 10 characters (and can carry 50 bits of entropy).
200200

201-
Now let's suppose we need to ensure the names of a handful of items are unique. Let's say 30 items. And let's decide we can live with a 1 in 100,000 probability of collision (we're just futzing with some code ideas). Using hex characters:
201+
Now let's suppose we need to ensure the names of a handful of items are unique. Let's say 30 items. And let's decide we can live with a 1 in 100,000 probability of collision (we're just futzing with some coding ideas). Using hex characters:
202202

203203
```js
204204
bits = entropy.bits(30, 100000)
205-
string = entropy.randomString(bits, entropy.charSet16)
205+
string = entropy.randomString(bits, entropy.charSet16, false)
206206
```
207207

208208
> String: dbf40a6
209209
210210
Using 4 characters:
211211

212212
```js
213-
string = entropy.randomString(bits, entropy.charSet4)
213+
string = entropy.randomString(bits, entropy.charSet4, false)
214214
```
215215

216216
> String: CGCCGTAGGATAT
217217
218-
Okay, we probably wouldn't use 4 characters (and what's up with those characters?), but you get the idea.
218+
Okay, we probably wouldn't use 4 characters (and what's up with those characters?), but you get the idea. The [Efficiency](#Efficiency) explains the 3rd argument of `false`.
219219

220220
Suppose we have a more extreme need. We want less than a 1 in a trillion chance that 10 billion base 32 strings repeat. Let's see, our risk (trillion) is 10 to the 12th and our total (10 billion) is 10 to the 10th, so:
221221

@@ -363,7 +363,7 @@ Compare that to the `entropy-string` scheme. For the example above, slicing off
363363

364364
But there is an even bigger issue with the above code from a security perspective. `Math.random` *is not a crytographically strong random number generator*. **_Do not_** use `Math.random` to create secure IDs! This highlights an important point. Strings are only capable of carrying information (entropy); it's the random bytes that actually provide the entropy itself. `entropy-string` automatically generates the necessary number of bytes needed to create a random string using the `crypto` library.
365365

366-
However, if you don't need cryptographically strong random strings, you can request `entropy-string` use `Math.random` rather than the `crypto` library to generate randomness:
366+
However, if you don't need cryptographically strong random strings, you can request `entropy-string` use `Math.random` rather than the `crypto` library by passing in a 3rd argument of `false`:
367367

368368
```js
369369
const entropy = require('entropy-string')
@@ -372,32 +372,32 @@ However, if you don't need cryptographically strong random strings, you can requ
372372

373373
> PQ9dmqJ7g6
374374
375-
When using `Math.random`, the `entropy-string` scheme uses 48 of the 52(ish) bits of randomness from each call to `Math.random`. That's more efficient than the above code snippet but less so than using `crypto` bytes.
375+
When using `Math.random`, the `entropy-string` scheme uses 48 of the 52(ish) bits of randomness from each call to `Math.random`. That's more efficient than the above code snippet but less so than using bytes from `crypto`.
376376

377377
Fortunately you don't need to really understand how the bytes are efficiently sliced and diced to get the string. But you may want to provide your own [Custom Bytes](#CustomBytes) to create a string, which is the next topic.
378378

379379
[TOC](#TOC)
380380

381381
## <a name="CustomBytes"></a>Custom Bytes
382382

383-
As described in [Efficiency](#Efficiency), `entropy-string` automatically generates random bytes using the `crypto` library. But you may have a need to provide your own bytes, say for deterministic testing or to use a specialized byte genterator. The `entropy.randomStringWithBytes` function allows passing in your own bytes to create a string.
383+
As described in [Efficiency](#Efficiency), `entropy-string` automatically generates random bytes using the `crypto` library. But you may have a need to provide your own bytes, say for deterministic testing or to use a specialized byte generator. The `entropy.randomString` function allows passing in your own bytes to create a string.
384384

385385
Suppose we want a string capable of 30 bits of entropy using 32 characters. We pass in 4 bytes (to cover the 30 bits):
386386

387387
```js
388388
const entropy = require('entropy-string')
389389

390-
let bytes: RandomString.Bytes = [250, 200, 150, 100]
391-
let string = entropy.randomStringWithBytes(30, entropy.charSet32, bytes)
390+
let bytes: RandomString.Bytes = new Uint8Array[250, 200, 150, 100]
391+
let string = entropy.randomString(30, entropy.charSet32, bytes)
392392
```
393393

394394
> string: Th7fjL
395395
396-
The __bytes__ provided can come from any source. However, the number of bytes must be sufficient to generate the string as described in the [Efficiency](#Efficiency) section. `entropy.randomStringWithBytes` throws an `Error` if the string cannot be formed from the passed bytes.
396+
The __bytes__ provided can come from any source. However, the number of bytes must be sufficient to generate the string as described in the [Efficiency](#Efficiency) section. `entropy.randomString` throws an `Error` if the string cannot be formed from the passed bytes.
397397

398398
```js
399399
try {
400-
string = entropy.randomStringWithBytes(32, entropy.charSet32, bytes)
400+
string = entropy.randomString(32, entropy.charSet32, bytes)
401401
}
402402
catch(error) {
403403
console.log(error.message)

dist/lib/entropy.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ var bitsWithPowers = function bitsWithPowers(tPower, rPower) {
7575
};
7676

7777
var randomString = function randomString(entropy, charSet) {
78-
var crypto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
78+
var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
7979

80-
var bytes = crypto ? _cryptoBytes(entropy, charSet) : _randomBytes(entropy, charSet);
80+
if (!(opt === null || opt instanceof Uint8Array || typeof opt == 'boolean')) {
81+
throw new Error('Optional 3rd argument must be either an Uint8Array or a boolean');
82+
}
83+
84+
var bytes = opt instanceof Uint8Array ? opt : opt === false ? _randomBytes(entropy, charSet) : _cryptoBytes(entropy, charSet);
8185
return randomStringWithBytes(entropy, charSet, bytes);
8286
};
8387

lib/entropy.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ const bitsWithPowers = (tPower, rPower) => {
5252
return N
5353
}
5454

55-
const randomString = (entropy, charSet, opt) => {
56-
let bytes = (opt instanceof Array) ? opt :
55+
const randomString = (entropy, charSet, opt = null) => {
56+
if ( !( (opt === null) || (opt instanceof Uint8Array) || (typeof opt == 'boolean') ) ) {
57+
throw new Error('Optional 3rd argument must be either an Uint8Array or a boolean')
58+
}
59+
60+
let bytes = (opt instanceof Uint8Array) ? opt :
5761
(opt === false) ? _randomBytes(entropy, charSet) : _cryptoBytes(entropy, charSet)
5862
return randomStringWithBytes(entropy, charSet, bytes)
5963
}

test/entropy.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ test('Custom 64 chars', t => {
453453
let charSet = entropy.charSet64
454454
try {
455455
charSet.use('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210_-')
456-
let bytes = [0x9d, 0x99, 0x4e, 0xa5, 0xd2, 0x3f, 0x8c, 0x86, 0x80]
456+
let bytes = new Uint8Array([0x9d, 0x99, 0x4e, 0xa5, 0xd2, 0x3f, 0x8c, 0x86, 0x80])
457457
let string = entropy.randomString(72, charSet, bytes)
458458

459459
t.is(string, 'NzLoPDi-JiAa')
@@ -471,7 +471,8 @@ test('Custom 32 chars', t => {
471471
let charSet = entropy.charSet32
472472
try {
473473
charSet.use('2346789BDFGHJMNPQRTbdfghjlmnpqrt')
474-
let string = entropy.randomString(55, charSet, [0xd2, 0xe3, 0xe9, 0xda, 0x19, 0x97, 0x52])
474+
let bytes = new Uint8Array([0xd2, 0xe3, 0xe9, 0xda, 0x19, 0x97, 0x52])
475+
let string = entropy.randomString(55, charSet, bytes)
475476
t.is(string, 'mHRrbgQlTqF')
476477
}
477478
catch(error) {
@@ -487,7 +488,7 @@ test('Custom 16 chars', t => {
487488
let charSet = entropy.charSet16
488489
try {
489490
charSet.use('0123456789ABCDEF')
490-
let string = entropy.randomString(20, charSet, [0xc7, 0xc9, 0x00])
491+
let string = entropy.randomString(20, charSet, new Uint8Array([0xc7, 0xc9, 0x00]))
491492
t.is(string, 'C7C90')
492493
}
493494
catch(error) {
@@ -503,7 +504,7 @@ test('Custom 8 chars', t => {
503504
let charSet = entropy.charSet8
504505
try {
505506
charSet.use('abcdefgh')
506-
let string = entropy.randomString(30, charSet, [0xc7, 0xc9, 0x07, 0xc9])
507+
let string = entropy.randomString(30, charSet, new Uint8Array([0xc7, 0xc9, 0x07, 0xc9]))
507508
t.is(string, 'gbheeeahgc')
508509
}
509510
catch(error) {
@@ -519,7 +520,7 @@ test('Custom 4 chars', t => {
519520
let charSet = entropy.charSet4
520521
try {
521522
charSet.use('atcg')
522-
let string = entropy.randomString(16, charSet, [0x20, 0xf1])
523+
let string = entropy.randomString(16, charSet, new Uint8Array([0x20, 0xf1]))
523524
t.is(string, 'acaaggat')
524525
}
525526
catch(error) {
@@ -535,7 +536,7 @@ test('Custom 2 chars', t => {
535536
let charSet = entropy.charSet2
536537
try {
537538
charSet.use('HT')
538-
let string = entropy.randomString(16, charSet, [0xe3, 0xe9])
539+
let string = entropy.randomString(16, charSet, new Uint8Array([0xe3, 0xe9]))
539540
t.is(string, 'TTTHHHTTTTTHTHHT')
540541
}
541542
catch(error) {
@@ -575,7 +576,7 @@ test('No crypto', t => {
575576

576577
const entropyString = (bits, charSet, arr) => {
577578
let bytes = Buffer.from(arr)
578-
return entropy.randomStringWithBytes(bits, charSet, bytes)
579+
return entropy.randomString(bits, charSet, bytes)
579580
}
580581

581582
const entropyStringLength = (bits, charSet) => {

0 commit comments

Comments
 (0)