Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Secret sharing for javascript

License

NotificationsYou must be signed in to change notification settings

amper5and/secrets.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NOTICE: This project is no longer maintained.

Take a look athttps://github.com/grempe/secrets.js for many improvements and enhancements on my original project.


See it in action athttp://passguardian.com

What is it?

secrets.js is an implementation ofShamir's threshold secret sharing scheme in javascript, for node.js and browsers.

It can be used to split any "secret" (i.e. a password, text file, Bitcoin private key, anything) inton number of "shares" (each the same size in bits as the original secret), requiring that exactly any numbert ("threshold") of them be present to reconstruct the original secret.

Examples:

Divide a 512-bit key, expressed in hexadecimal form, into 10 shares, requiring that any 5 of them are necessary to reconstruct the original key:

// generate a 512-bit keyvar key = secrets.random(512); // => key is a hex string// split into 10 shares with a threshold of 5var shares = secrets.share(key, 10, 5); // => shares = ['801xxx...xxx','802xxx...xxx','803xxx...xxx','804xxx...xxx','805xxx...xxx']// combine 4 sharesvar comb = secrets.combine( shares.slice(0,4) );console.log(comb === key); // => false// combine 5 sharesvar comb = secrets.combine( shares.slice(4,9) );console.log(comb === key); // => true// combine ALL sharesvar comb = secrets.combine( shares );console.log(comb === key); // => true// create another share with id 8var newShare = secrets.newShare(8, shares); // => newShare = '808xxx...xxx'// reconstruct using 4 original shares and the new share:var comb = secrets.combine( shares.slice(1,5).concat(newShare) );console.log(comb === key); // => true

Divide a password containing a mix of numbers, letters, and other characters, requiring that any 3 shares must be present to reconstruct the original password:

var pw = '<<PassWord123>>';// convert the text into a hex stringvar pwHex = secrets.str2hex(pw); // => hex string// split into 5 shares, with a threshold of 3var shares = secrets.share(pwHex, 5, 3);// combine 2 shares:var comb = secrets.combine( shares.slice(1,3) );//convert back to UTF string:comb = secrets.hex2str(comb);console.log( comb === pw  ); // => false// combine 3 shares:var comb = secrets.combine( [ shares[1], shares[3], shares[4] ] );//convert back to UTF string:comb = secrets.hex2str(comb);console.log( comb === pw  ); // => true

Installation and usage

secrets.js is available onnpm. Install using

npm install secrets.js

The version on npm may not always reflect all the latest changes, especially during times of heavy development. To get the most up-to-date version, downloadthe current master zip file, then run the following code from inside the folder:

npm install

To use it in node.js:

var secrets = require('secrets.js');

To use it in the browser, includesecrets.js orsecrets.min.js (minified using Google Closure Compiler)

<script src="secrets.min.js"></script>

API

  • secrets.share()
  • secrets.combine()
  • secrets.newShare()
  • secrets.init()
  • secrets.getConfig()
  • secrets.setRNG()
  • secrets.random()
  • secrets.str2hex()
  • secrets.hex2str()

secrets.share( secret, numShares, threshold, [padLength] )

Divide asecret expressed in hexadecimal form intonumShares number of shares, requiring thatthreshold number of shares be present for reconstructing thesecret;

  • secret: String, required: A hexadecimal string.
  • numShares: Number, required: The number of shares to compute. This must be an integer between 2 and 2^bits-1 (seesecrets.init() below for explanation ofbits).
  • threshold: Number, required: The number of shares required to reconstruct the secret. This must be an integer between 2 and 2^bits-1 (seesecrets.init() below for explanation ofbits).
  • padLength: Number, optional, default0: How much to zero-pad the binary representation ofsecret. This ensures a minimum length for each share. See "Note on security" below.

The output ofsecrets.share() is an Array of lengthnumShares. Each item in the array is a String. SeeShare format below for information on the format.

secrets.combine( shares )

Reconstructs a secret fromshares.

  • shares: Array, required: An Array of shares. The form is equivalent to the output fromsecrets.share().

The output ofsecrets.combine() is a String representing the reconstructed secret. Note that this function will ALWAYS produce an output String. However, if the number ofshares that are provided is not thethreshold number of shares, the outputwill not be the originalsecret. In order to guarantee that the original secret is reconstructed, the correctthreshold number of shares must be provided.

Note that usingmore than thethreshold number of shares will also result in an accurate reconstruction of the secret. However, using more shares adds to computation time.

secrets.newShare( id, shares )

Create a new share from the input shares.

  • id: Number or String, required: A Number representing the share id. The id is an integer between 1 and 2^bits-1. It can be entered as a Number or a number String expressed in hexadecimal form.
  • shares: Array, required: The array of shares (in the same format as outputted fromsecrets.share()) that can be used to reconstruct the originalsecret.

The output ofsecrets.newShare() is a String. This is the same format for the share thatsecrets.share() outputs. Note that this function ALWAYS produces an output String. However, as forsecrets.combine(), if the number ofshares that are entered is not thethreshold number of shares, the output sharewill not be a valid share (i.e.will not be useful in reconstructing the original secret). In order to guarantee that the share is valid, the correctthreshold number of shares must be provided.

secrets.init( [bits] )

Set the number of bits to use for finite field arithmetic.

  • bits: Number, optional, default8: An integer between 3 and 20. The number of bits to use for the Galois field.

Internally, secrets.js uses finite field arithmetic in binary Galois Fields of size 2^bits. Multiplication is implemented by the means of log and exponential tables. Before any arithmetic is performed, the log and exp tables are pre-computed. Each table contains 2^bits entries.

bits is the limiting factor onnumShares andthreshold. The maximum number of shares possible for a particularbits is (2^bits)-1 (the zeroth share cannot be used as it is thesecret by definition.). By default, secrets.js uses 8 bits, for a total 2^8-1 = 255 possible number of shares. To compute more shares, a larger field must be used. To compute the number of bits you will need for yournumShares orthreshold, compute the log-base2 of (numShares+1) and round up, i.e. in #"auto">Note:

  • secrets.init() does NOT need to be called if you plan on using the default of 8 bits. It is automatically called on loading the library.
  • The size of the exp and log tables depends onbits (each has 2^bits entries). Therefore, using a large number of bits will cause a slightly longer delay to compute the tables.
  • Thetheoretical maximum number of bits is 31, as javascript performs bitwise operations on 31-bit numbers. A limit of 20 bits has been hard-coded into secrets.js, which can produce 1,048,575 shares. secrets.js has not been tested with this many shares, and it is not advisable to go this high, as it may be too slow to be of any practical use.
  • The Galois Field may be re-initialized to a new setting whensecrets.newShare() orsecrets.combine() are called with shares that are from a different Galois Field than the currently initialized one. For this reason, usesecrets.getConfig() (see below) to check what the current bit-setting is.

secrets.getConfig()

Returns an Object with the current configuration. Has the following properties:

  • bits: [Number] The number of bits used for the current initialized finite field
  • unsafePRNG: [Boolean]: Istrue whenMath.random() is being used as the PRNG

secrets.setRNG( function(bits){} )

Set the pseudo-random number generator used to compute shares.

secrets.js uses a PRNG in thesecrets.share() andsecrets.random() functions. By default, it tries to use a cryptographically strong PRNG. In node.js this iscrypto.randomBytes(). In browsers that support it, it iscrypto.getRandomValues() (using typed arrays, which must be supported too). If neither of these are available it defaults to usingMath.random(), which is NOT cryptographically strong (except reportedly in Safari, though I have yet to confirm this). A warning will be displayed in the console and in an alert box in browsers whenMath.random() is being used.

To supply your own PRNG, usesecrets.setRNG(). It expects a Function of the formfunction(bits){}. It should compute a random integer between 1 and 2^bits-1. The output must be a String of lengthbits containing random 1's and 0's (cannot be ALL 0's). Whensecrets.setRNG() is called, it tries to check the PRNG to make sure it complies with some of these demands, but obviously it's not possible to run through all possible outputs. So make sure that it works correctly.

If you are just planning on usingsecrets.combine() orsecrets.newShare(), then no PRNG is required. It is only used by thesecrets.share() andsecrets.random() functions.

NOTE: In a near-future version of secrets.js, the requirement for the PRNG function will be less convoluted. It probably will just have to return a random integer between 1 andmax, or something like that.

secrets.random( bits )

Generate a randombits-length string, and output it in hexadecimal format.bits must be an integer greater than 1.

secrets.str2hex( str, [bytesPerChar] )

Convert a UTF stringstr into a hexadecimal string, usingbytesPerChar bytes (octets) for each character.

  • str: String, required: A UTF string.
  • bytesPerChar: Number, optional, default2. The maximumbytesPerChar is 6 to ensure that each character is represented by a number that is below javascript's 2^53 maximum for integers.

secrets.hex2str( str, [bytesPerChar] )

Convert a hexadecimal string into a UTF string. Each character of the output string is represented bybytesPerChar bytes in the Stringstr. See note onbytesPerChar undersecrets.str2hex() above.

Share format

Each share is a string in the format<bits><id><value>. Each part of the string is described below:

  • bits: The first character, expressed in base-36 format, is the number of bits used for the Galois Field. This number must be between 3 and 20, expressed by the characters [3-9, a-k].
  • id: The id of the share. This is a number between 1 and 2^bits-1, expressed in hexadecimal form. The number of characters used to represent the id is the character-length of the representation of the maximum id (2^bits-1) in hexadecimal:(Math.pow(2,bits)-1).toString(16).length.
  • value: The value of the share, expressed in hexadecimal form. The length of this string depends on the length of the secret.

Note on security

Shamir's secret sharing scheme is "information-theoretically secure" and "perfectly secure" in that less than the requisite number of shares provide no information about the secret (i.e. knowing less than the requisite number of shares is the same as knowing none of the shares). However, because the size of each share is the same as the size of the secret (when using binary Galois fields, as secrets.js does), in practice it does leaksome information, namely thesize of the secret. Therefore, if you will be using secrets.js to shareshort password strings (which can be brute-forced much more easily than longer ones), it would be wise to zero-pad them so that the shares do not leak information about the size of the secret.

Whensecrets.share() is called with apadLength, thesecret is zero-padded so that it's length is a multiple of the padLength. The second example above can be modified to use 1024-bit zero-padding, producing longer shares:

var pw = '<<PassWord123>>';// convert the text into a hex stringvar pwHex = secrets.str2hex(pw); // => 240-bit password// split into 5 shares, with a threshold of 3, WITH zero-paddingvar shares = secrets.share(pwHex, 5, 3, 1024); // => 1024-bit shares// combine 3 sharesvar comb = secrets.combine( [ shares[1], shares[3], shares[4] ] );// convert back to UTF stringcomb = secrets.hex2str(comb);console.log( comb === pw  ); // => true

License

secrets.js is released under the MIT License. SeeLICENSE.

Changelog

  • 0.1.8: bugfix release
  • 0.1.7: added config.unsafePRNG reset when supplying a new PRNG
  • 0.1.6:
    • Removed JSBN dependency, support for arbitrary radices, and theconvertBase() function, with attendant 50% file size reduction.
    • Fixed bug where leading zeros were dropped.
    • Renamed string conversion functions.
  • 0.1.5: getConfig() returns information about PRNG
  • 0.1.4: new share format

Possible future enhancements

About

Secret sharing for javascript

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp