New probabilistic random number generation algorithms; UNTESTED
This commit is contained in:
parent
3b912d2fae
commit
168a6b0bb8
135
src/crypto/public_key/prime.js
Normal file
135
src/crypto/public_key/prime.js
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// OpenPGP.js - An OpenPGP implementation in javascript
|
||||||
|
// Copyright (C) 2018 Proton Technologies AG
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 3.0 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
// Algorithms for probabilistic primality testing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires bn.js
|
||||||
|
* @requires crypto/random
|
||||||
|
* @module crypto/public_key/prime
|
||||||
|
*/
|
||||||
|
|
||||||
|
import BN from 'bn.js';
|
||||||
|
import random from '../random';
|
||||||
|
|
||||||
|
function randomProbablePrime(b) {
|
||||||
|
let n;
|
||||||
|
const min = new BN(1).shln(b-1);
|
||||||
|
do {
|
||||||
|
n = random.getRandomBN(min, min.shln(1));
|
||||||
|
if (n.isEven()) {
|
||||||
|
n.iaddn(1); // force odd
|
||||||
|
}
|
||||||
|
} while (!isProbablePrime(n));
|
||||||
|
// this.dAddOffset(2, 0);
|
||||||
|
// if (this.bitLength() > b)
|
||||||
|
// this.subTo(BigInteger.ONE.shiftLeft(b - 1), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isProbablePrime(n) {
|
||||||
|
if (!fermat(n)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!millerRabin(n)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether n is probably prime or not using Fermat's test with b = 2.
|
||||||
|
* Fails if b^(n-1) mod n === 1.
|
||||||
|
*/
|
||||||
|
export function fermat(n, b) {
|
||||||
|
b = b || new BN(2);
|
||||||
|
return b.toRed(BN.mont(n)).redPow(n.subn(1)).cmpn(1) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Miller-Rabin - Miller Rabin algorithm for primality test
|
||||||
|
// Copyright Fedor Indutny, 2014.
|
||||||
|
//
|
||||||
|
// This software is licensed under the MIT License.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
// Adapted on Jan 2018 from version 4.0.1 at https://github.com/indutny/miller-rabin
|
||||||
|
// TODO check this against jsbn's bnpMillerRabin
|
||||||
|
// TODO implement fixed base Miller-Rabin; for instance by writing a function that
|
||||||
|
// picks a number within the given range from a precomputed list of primes.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether n is probably prime or not using the Miller-Rabin test.
|
||||||
|
* See HAC Remark 4.28.
|
||||||
|
*/
|
||||||
|
export function millerRabin(n, k, cb) {
|
||||||
|
var len = n.bitLength();
|
||||||
|
var red = BN.mont(n);
|
||||||
|
var rone = new BN(1).toRed(red);
|
||||||
|
|
||||||
|
if (!k)
|
||||||
|
k = Math.max(1, (len / 48) | 0);
|
||||||
|
|
||||||
|
// Find d and s, (n - 1) = (2 ^ s) * d;
|
||||||
|
var n1 = n.subn(1);
|
||||||
|
for (var s = 0; !n1.testn(s); s++) {}
|
||||||
|
var d = n.shrn(s);
|
||||||
|
|
||||||
|
var rn1 = n1.toRed(red);
|
||||||
|
|
||||||
|
var prime = true;
|
||||||
|
for (; k > 0; k--) {
|
||||||
|
var a = random.getRandomBN(new BN(2), n1);
|
||||||
|
if (cb)
|
||||||
|
cb(a);
|
||||||
|
|
||||||
|
var x = a.toRed(red).redPow(d);
|
||||||
|
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (var i = 1; i < s; i++) {
|
||||||
|
x = x.redSqr();
|
||||||
|
|
||||||
|
if (x.cmp(rone) === 0)
|
||||||
|
return false;
|
||||||
|
if (x.cmp(rn1) === 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i === s)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prime;
|
||||||
|
};
|
|
@ -20,6 +20,7 @@
|
||||||
/**
|
/**
|
||||||
* @requires bn.js
|
* @requires bn.js
|
||||||
* @requires asmcrypto.js
|
* @requires asmcrypto.js
|
||||||
|
* @requires crypto/public_key/prime
|
||||||
* @requires crypto/random
|
* @requires crypto/random
|
||||||
* @requires config
|
* @requires config
|
||||||
* @requires util
|
* @requires util
|
||||||
|
@ -31,6 +32,7 @@ import BN from 'bn.js';
|
||||||
import { RSA } from 'asmcrypto.js/src/rsa/exports-keygen';
|
import { RSA } from 'asmcrypto.js/src/rsa/exports-keygen';
|
||||||
import { RSA_RAW } from 'asmcrypto.js/src/rsa/exports-raw';
|
import { RSA_RAW } from 'asmcrypto.js/src/rsa/exports-raw';
|
||||||
import { random as asmcrypto_random } from 'asmcrypto.js/src/random/exports';
|
import { random as asmcrypto_random } from 'asmcrypto.js/src/random/exports';
|
||||||
|
import prime from './prime';
|
||||||
import random from '../random';
|
import random from '../random';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import util from '../../util';
|
import util from '../../util';
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a secure random MPI in specified range
|
* Create a secure random MPI that is greater than or equal to min and less than max.
|
||||||
* @param {module:type/mpi} min Lower bound, included
|
* @param {module:type/mpi} min Lower bound, included
|
||||||
* @param {module:type/mpi} max Upper bound, excluded
|
* @param {module:type/mpi} max Upper bound, excluded
|
||||||
* @return {module:BN} Random MPI
|
* @return {module:BN} Random MPI
|
||||||
|
@ -107,18 +107,19 @@ export default {
|
||||||
throw new Error('Illegal parameter value: max <= min');
|
throw new Error('Illegal parameter value: max <= min');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let r;
|
||||||
const modulus = max.sub(min);
|
const modulus = max.sub(min);
|
||||||
const length = modulus.byteLength();
|
const length = modulus.byteLength();
|
||||||
let r = new BN(this.getRandomBytes(length));
|
|
||||||
// Using a while loop is necessary to avoid bias
|
// Using a while loop is necessary to avoid bias
|
||||||
while (r.cmp(modulus) >= 0) {
|
do {
|
||||||
r = new BN(this.getRandomBytes(length));
|
r = new BN(this.getRandomBytes(length));
|
||||||
}
|
} while (r.cmp(modulus) >= 0);
|
||||||
|
|
||||||
return r.iadd(min);
|
return r.iadd(min);
|
||||||
},
|
},
|
||||||
|
|
||||||
randomBuffer: new RandomBuffer()
|
randomBuffer: new RandomBuffer()
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,8 +21,7 @@
|
||||||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of type MPI ({@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2})<br/>
|
* Implementation of type MPI ({@link https://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2})
|
||||||
* <br/>
|
|
||||||
* Multiprecision integers (also called MPIs) are unsigned integers used
|
* Multiprecision integers (also called MPIs) are unsigned integers used
|
||||||
* to hold large integers such as the ones used in cryptographic
|
* to hold large integers such as the ones used in cryptographic
|
||||||
* calculations.
|
* calculations.
|
||||||
|
@ -67,7 +66,7 @@ MPI.prototype.read = function (bytes, endian='be') {
|
||||||
}
|
}
|
||||||
|
|
||||||
const bits = (bytes[0] << 8) | bytes[1];
|
const bits = (bytes[0] << 8) | bytes[1];
|
||||||
const bytelen = Math.ceil(bits / 8);
|
const bytelen = (bits + 7) >>> 3;
|
||||||
const payload = bytes.subarray(2, 2 + bytelen);
|
const payload = bytes.subarray(2, 2 + bytelen);
|
||||||
|
|
||||||
if (endian === 'le') {
|
if (endian === 'le') {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user