private void computeShuffleIndices(@NotNull final DigestRandomGenerator digestRandomGenerator, final int keyConsumptionIncrement, @NotNull final byte[] key) { int keyBytesConsumed = 0; final int maxIndex = encryptedLength * 8; @NotNull final byte[] randomByteBuffer = new byte[8]; for (long i = 0; i < maxIndex; i++) { if (0 == i % keyConsumptionIncrement) { keyBytesConsumed = consumeKeyBytes(digestRandomGenerator, keyBytesConsumed, keyConsumptionIncrement, key); } digestRandomGenerator.nextBytes(randomByteBuffer); long randomIndex = bytesToLong(randomByteBuffer) % (i + 1); if (randomIndex != i) { targetIndices[(int) (i % 8)][(int) (i / 8)] = targetIndices[(int) (randomIndex % 8)][(int) (randomIndex / 8)]; } targetIndices[(int) (randomIndex % 8)][(int) (randomIndex / 8)] = i; } }
private void doExpectedTest(Digest digest, int seed, byte[] expected, byte[] noCycle) { DigestRandomGenerator rGen = new DigestRandomGenerator(digest); byte[] output = new byte[digest.getDigestSize()]; rGen.addSeedMaterial(seed); for (int i = 0; i != 1024; i++) { rGen.nextBytes(output); } if (noCycle != null) { if (Arrays.areEqual(noCycle, output)) { fail("seed not being cycled!"); } } if (!Arrays.areEqual(expected, output)) { fail("expected output doesn't match"); } }
private void doExpectedTest(Digest digest, byte[] seed, byte[] expected) { DigestRandomGenerator rGen = new DigestRandomGenerator(digest); byte[] output = new byte[digest.getDigestSize()]; rGen.addSeedMaterial(seed); for (int i = 0; i != 1024; i++) { rGen.nextBytes(output); } if (!Arrays.areEqual(expected, output)) { fail("expected output doesn't match"); } }
/** * Compute values needed to encrypt. * * @param plaintext The plain text to be encrypted. * @param key The encryption key. * @throws IllegalArgumentException if the length of plaintext is greater than {@value MAX_LENGTH}. */ @NotNull static EncryptionValues forEncryption(@NotNull final byte[] plaintext, @NotNull final byte[] key) { if (plaintext.length > MAX_LENGTH) { throw new IllegalArgumentException("Plaintext is longer than maximum supported length of " + MAX_LENGTH); } @NotNull EncryptionValues ev = new EncryptionValues(); ev.padLength = plaintext.length; ev.encryptedLength = plaintext.length + ev.padLength; ev.targetIndices = new long[8][ev.encryptedLength]; @NotNull DigestRandomGenerator digestRandomGenerator = createDigestRandomGenerator(); int keyConsumptionIncrement = computeKeyConsumptionIncrement(key.length, plaintext.length); ev.computeShuffleIndices(digestRandomGenerator, keyConsumptionIncrement, key); return ev; }
/** * Compute values needed to decrypt. * * @param encrypted The encrypted text to be decrypted. * @param key The encryption key. */ @NotNull static EncryptionValues forDecryption(@NotNull final byte[] encrypted, @NotNull final byte[] key) { @NotNull EncryptionValues ev = new EncryptionValues(); ev.encryptedLength = encrypted.length - 1; ev.padLength = encrypted.length / 2; ev.targetIndices = new long[8][ev.encryptedLength]; @NotNull DigestRandomGenerator digestRandomGenerator = createDigestRandomGenerator(); int keyConsumptionIncrement = computeKeyConsumptionIncrement(key.length, encrypted.length / 2); ev.computeShuffleIndices(digestRandomGenerator, keyConsumptionIncrement, key); return ev; }
private int consumeKeyBytes(@NotNull final DigestRandomGenerator digestRandomGenerator, final int keyBytesConsumed, final int keyConsumptionIncrement, @NotNull final byte[] key) { final int keyBytesRemaining = key.length - keyBytesConsumed; if (keyBytesRemaining > 0) { int bytesToConsume = (keyBytesRemaining > keyConsumptionIncrement) ? keyConsumptionIncrement : keyBytesRemaining; @NotNull byte[] keyBuffer = new byte[bytesToConsume]; System.arraycopy(key, keyBytesConsumed, keyBuffer, 0, bytesToConsume); digestRandomGenerator.addSeedMaterial(keyBuffer); return keyBytesConsumed + bytesToConsume; } return keyBytesConsumed; }
AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters) { Digest d = TlsUtils.createHash(HashAlgorithm.sha256); byte[] seed = new byte[d.getDigestSize()]; secureRandom.nextBytes(seed); this.nonceRandom = new DigestRandomGenerator(d); nonceRandom.addSeedMaterial(nextCounterValue()); nonceRandom.addSeedMaterial(Times.nanoTime()); nonceRandom.addSeedMaterial(seed); this.secureRandom = secureRandom; this.securityParameters = securityParameters; }
public byte[] messageEncrypt(byte[] input) throws Exception { int kDiv8 = k >> 3; // generate random r of length k div 8 bytes byte[] r = new byte[kDiv8]; sr.nextBytes(r); // generate random vector r' of length k bits GF2Vector rPrime = new GF2Vector(k, sr); // convert r' to byte array byte[] rPrimeBytes = rPrime.getEncoded(); // compute (input||r) byte[] mr = ByteUtils.concatenate(input, r); // compute H(input||r) messDigest.update(mr, 0, mr.length); byte[] hmr = new byte[messDigest.getDigestSize()]; messDigest.doFinal(hmr, 0); // convert H(input||r) to error vector z GF2Vector z = Conversions.encode(n, t, hmr); // compute c1 = E(rPrime, z) byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, rPrime, z).getEncoded(); // get PRNG object DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); // seed PRNG with r' sr0.addSeedMaterial(rPrimeBytes); // generate random c2 byte[] c2 = new byte[input.length + kDiv8]; sr0.nextBytes(c2); // XOR with input for (int i = 0; i < input.length; i++) { c2[i] ^= input[i]; } // XOR with r for (int i = 0; i < kDiv8; i++) { c2[input.length + i] ^= r[i]; } // return (c1||c2) return ByteUtils.concatenate(c1, c2); }
public byte[] messageDecrypt(byte[] input) throws Exception { int c1Len = (n + 7) >> 3; int c2Len = input.length - c1Len; // split cipher text (c1||c2) byte[][] c1c2 = ByteUtils.split(input, c1Len); byte[] c1 = c1c2[0]; byte[] c2 = c1c2[1]; // decrypt c1 ... GF2Vector c1Vec = GF2Vector.OS2VP(n, c1); GF2Vector[] c1Dec = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, c1Vec); byte[] rPrimeBytes = c1Dec[0].getEncoded(); // ... and obtain error vector z GF2Vector z = c1Dec[1]; // get PRNG object DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); // seed PRNG with r' sr0.addSeedMaterial(rPrimeBytes); // generate random sequence byte[] mrBytes = new byte[c2Len]; sr0.nextBytes(mrBytes); // XOR with c2 to obtain (m||r) for (int i = 0; i < c2Len; i++) { mrBytes[i] ^= c2[i]; } // compute H(m||r) messDigest.update(mrBytes, 0, mrBytes.length); byte[] hmr = new byte[messDigest.getDigestSize()]; messDigest.doFinal(hmr, 0); // compute Conv(H(m||r)) c1Vec = Conversions.encode(n, t, hmr); // check that Conv(H(m||r)) = z if (!c1Vec.equals(z)) { throw new Exception("Bad Padding: Invalid ciphertext."); } // split (m||r) to obtain m int kDiv8 = k >> 3; byte[][] mr = ByteUtils.split(mrBytes, c2Len - kDiv8); // return plain text m return mr[0]; }
public byte[] messageEncrypt(byte[] input) throws Exception { // generate random vector r of length k bits GF2Vector r = new GF2Vector(k, sr); // convert r to byte array byte[] rBytes = r.getEncoded(); // compute (r||input) byte[] rm = ByteUtils.concatenate(rBytes, input); // compute H(r||input) messDigest.update(rm, 0, rm.length); byte[] hrm = new byte[messDigest.getDigestSize()]; messDigest.doFinal(hrm, 0); // convert H(r||input) to error vector z GF2Vector z = Conversions.encode(n, t, hrm); // compute c1 = E(r, z) byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, r, z) .getEncoded(); // get PRNG object DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); // seed PRNG with r' sr0.addSeedMaterial(rBytes); // generate random c2 byte[] c2 = new byte[input.length]; sr0.nextBytes(c2); // XOR with input for (int i = 0; i < input.length; i++) { c2[i] ^= input[i]; } // return (c1||c2) return ByteUtils.concatenate(c1, c2); }
public byte[] messageDecrypt(byte[] input) throws Exception { int c1Len = (n + 7) >> 3; int c2Len = input.length - c1Len; // split ciphertext (c1||c2) byte[][] c1c2 = ByteUtils.split(input, c1Len); byte[] c1 = c1c2[0]; byte[] c2 = c1c2[1]; // decrypt c1 ... GF2Vector hrmVec = GF2Vector.OS2VP(n, c1); GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, hrmVec); byte[] rBytes = decC1[0].getEncoded(); // ... and obtain error vector z GF2Vector z = decC1[1]; // get PRNG object DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); // seed PRNG with r' sr0.addSeedMaterial(rBytes); // generate random sequence byte[] mBytes = new byte[c2Len]; sr0.nextBytes(mBytes); // XOR with c2 to obtain m for (int i = 0; i < c2Len; i++) { mBytes[i] ^= c2[i]; } // compute H(r||m) byte[] rmBytes = ByteUtils.concatenate(rBytes, mBytes); byte[] hrm = new byte[messDigest.getDigestSize()]; messDigest.update(rmBytes, 0, rmBytes.length); messDigest.doFinal(hrm, 0); // compute Conv(H(r||m)) hrmVec = Conversions.encode(n, t, hrm); // check that Conv(H(m||r)) = z if (!hrmVec.equals(z)) { throw new Exception("Bad Padding: invalid ciphertext"); } // return plaintext m return mBytes; }
private static DigestRandomGenerator createDigestRandomGenerator() { return new DigestRandomGenerator(new SHA512Digest()); }
private void doCountTest(Digest digest, byte[] seed, byte[] expectedXors) { DigestRandomGenerator rGen = new DigestRandomGenerator(digest); byte[] output = new byte[digest.getDigestSize()]; int[] averages = new int[digest.getDigestSize()]; byte[] ands = new byte[digest.getDigestSize()]; byte[] xors = new byte[digest.getDigestSize()]; byte[] ors = new byte[digest.getDigestSize()]; rGen.addSeedMaterial(seed); for (int i = 0; i != 1000000; i++) { rGen.nextBytes(output); for (int j = 0; j != output.length; j++) { averages[j] += output[j] & 0xff; ands[j] &= output[j]; xors[j] ^= output[j]; ors[j] |= output[j]; } } for (int i = 0; i != output.length; i++) { if ((averages[i] / 1000000) != 127) { fail("average test failed for " + digest.getAlgorithmName()); } if (ands[i] != 0) { fail("and test failed for " + digest.getAlgorithmName()); } if ((ors[i] & 0xff) != 0xff) { fail("or test failed for " + digest.getAlgorithmName()); } if (xors[i] != expectedXors[i]) { fail("xor test failed for " + digest.getAlgorithmName()); } } }
protected EntropyGathererBase(String name) { jvmRandom = new SecureRandom(); random = new DigestRandomGenerator(new SHA512Digest()); spi = new SecureRandomSpi() { private boolean init = true; protected final void engineSetSeed(byte[] seed) { random.addSeedMaterial(seed); } protected final void engineNextBytes(byte[] bytes) { if(init) { // initialize generator with randomness from jvm random.addSeedMaterial(jvmRandom.generateSeed(256)); init = false; } else { random.addSeedMaterial(jvmRandom.nextLong()); } random.addSeedMaterial(System.currentTimeMillis()); random.addSeedMaterial(Runtime.getRuntime().freeMemory()); random.addSeedMaterial(System.nanoTime()); random.nextBytes(bytes); } protected final byte[] engineGenerateSeed(int numBytes) { byte[] b = new byte[numBytes]; engineNextBytes(b); return b; } }; provider = new Provider(name, 1.2, "andy goryachev") { }; }