/* BlumBlumShub.java: implementation of the Blum Blum Shub PRNG Copyright 2005 Mark Rossmiller. This file is released under the GPL. BlumBlumShub.java is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. BlumBlumShub.java 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 General Public License for more details. You should have received a copy of the GNU General Public License along with BlumBlumShub.java; see the file LICENSE. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.dicarlo; import java.lang.Double; import java.lang.Math; import java.math.BigInteger; import java.security.SecureRandom; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Locale; import java.util.ResourceBundle; public class BlumBlumShub extends SecureRandom { /** * */ private static final long serialVersionUID = 6064623237295980749L; private BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE); private static int MINKEYLEN = 16; private static SecureRandom rng = new SecureRandom(); public int key_bitlen; public boolean improved; public BigInteger n, x; ResourceBundle rb = ResourceBundle.getBundle("MyResources", Locale.getDefault()); MainWindow mainWindow=null; public void gen_blumint() { //if (key_bitlen < this.MINKEYLEN) // return(); // THROW int pbits = ((this.key_bitlen)/2 + 1); int qbits = (this.key_bitlen)/2 + (this.key_bitlen%2); BigInteger p,q; for( p = BigInteger.probablePrime(pbits, rng); ! p.testBit(1); p = BigInteger.probablePrime(pbits, rng) ) ; for( q = BigInteger.probablePrime(qbits, rng); ! q.testBit(1); q = BigInteger.probablePrime(qbits, rng) ) ; this.n = p.multiply(q); this.key_bitlen = this.n.toString(2).length(); } public void gen_x() { Double seedBytes = new Double( Math.ceil(this.key_bitlen / 8.0) ); byte seed[] = rng.generateSeed( seedBytes.intValue() ); this.x = new BigInteger(1, seed); while ( this.x.gcd(this.n).compareTo(BigInteger.ONE) != 0) { this.x.add(BigInteger.ONE); } // x[0] = x^2 (mod n) this.x = this.x.modPow(TWO, n); } public byte[] randBytes(int nbytes) { ByteArrayOutputStream alist = new ByteArrayOutputStream(); if (this.improved == false) { /* basic implementation (only keep parity) */ { int i; for (i=0;i<nbytes;i++) { int j; int b = 0; /* we keep the parity (least significant bit) */ for (j=7;j>=0;j--) { /* x[n+1] = x[n]^2 (mod blumint) */ this.x = this.x.modPow(TWO, n); if (this.x.testBit(0)) b |= (1 << j); } alist.write(b); } return(alist.toByteArray()); } } else { /* improved implementation (keep log2(log2(n)) bits */ int loglogblum = new Double( Math.log(1.0 * this.key_bitlen) / Math.log(2.0) ).intValue(); int byt=0, bit=0, b=0, i; int perc=0; int prevperc=-1; for (;;) { /* x[n+1] = x[n]^2 (mod blumint) */ this.x = this.x.modPow(TWO, n); for (i=0;i<loglogblum;i++) { if (byt == nbytes) return(alist.toByteArray()); /* get the ith bit of x */ if (this.x.testBit(i)) b |= (1 << (7 - bit) ); if (bit == 7) { alist.write(b); byt++; b=0; bit=0; } else { bit++; } } } } } public ArrayList randInt(int base, int nmemb) { int i; ArrayList rndint = new ArrayList(); /* we waste a few precious bits here unless we're a power of 256 */ Double nbytes = new Double( Math.ceil( nmemb * ( Math.log(base) / Math.log(256.0) ) ) ); byte rndbuf[] = randBytes(nbytes.intValue()); BigInteger bn = new BigInteger(1, rndbuf); for (i=0;i<nmemb+1;i++) { BigInteger tmp = new BigInteger(new Integer(base).toString()); BigInteger q; tmp = tmp.pow( nmemb - i ); q = bn.divide(tmp); if (i>0) rndint.add(new Integer(q.intValue())); tmp = q.multiply(tmp); bn = bn.subtract(tmp); } return(rndint); } BlumBlumShub(int keybits) { byte trash[] = rng.generateSeed(1024); this.rng.nextBytes(trash); this.key_bitlen = keybits; this.improved = true; this.gen_blumint(); this.gen_x(); } public void setSeed(byte[]b){ super.setSeed(b); } }