/** * Encrypt a plaintext using the given key and nonce. * * @param nonce a 24-byte nonce (cf. {@link #nonce(ByteString)}, {@link #nonce()}) * @param plaintext an arbitrary message * @return the ciphertext */ public ByteString seal(@Nonnull ByteString nonce, @Nonnull ByteString plaintext) { // initialize XSalsa20 final XSalsa20Engine xsalsa20 = new XSalsa20Engine(); xsalsa20.init(true, new ParametersWithIV(new KeyParameter(key), nonce.toByteArray())); // generate Poly1305 subkey final byte[] sk = new byte[32]; xsalsa20.processBytes(sk, 0, 32, sk, 0); // encrypt plaintext final byte[] out = new byte[plaintext.size() + 16]; xsalsa20.processBytes(plaintext.toByteArray(), 0, plaintext.size(), out, 16); // hash ciphertext and prepend mac to ciphertext final Poly1305 poly1305 = new Poly1305(); poly1305.init(new KeyParameter(sk)); poly1305.update(out, 16, plaintext.size()); poly1305.doFinal(out, 0); return ByteString.of(out); }
/** * Decrypt a ciphertext using the given key and nonce. * * @param nonce a 24-byte nonce * @param ciphertext the encrypted message * @return an {@link Optional} of the original plaintext, or if either the key, nonce, or * ciphertext was modified, an empty {@link Optional} * @see #nonce(ByteString) * @see #nonce() */ public Optional<ByteString> open(@Nonnull ByteString nonce, @Nonnull ByteString ciphertext) { final byte[] in = ciphertext.toByteArray(); final XSalsa20Engine xsalsa20 = new XSalsa20Engine(); final Poly1305 poly1305 = new Poly1305(); // initialize XSalsa20 xsalsa20.init(false, new ParametersWithIV(new KeyParameter(key), nonce.toByteArray())); // generate mac subkey final byte[] sk = new byte[32]; xsalsa20.processBytes(sk, 0, sk.length, sk, 0); // hash ciphertext poly1305.init(new KeyParameter(sk)); final int len = Math.max(ciphertext.size() - 16, 0); poly1305.update(in, 16, len); final byte[] calculatedMAC = new byte[16]; poly1305.doFinal(calculatedMAC, 0); // extract mac final byte[] presentedMAC = new byte[16]; System.arraycopy(in, 0, presentedMAC, 0, Math.min(ciphertext.size(), 16)); // compare macs if (!MessageDigest.isEqual(calculatedMAC, presentedMAC)) { return Optional.empty(); } // decrypt ciphertext final byte[] plaintext = new byte[len]; xsalsa20.processBytes(in, 16, plaintext.length, plaintext, 0); return Optional.of(ByteString.of(plaintext)); }
protected byte[] calculateRecordMAC(KeyParameter macKey, byte[] additionalData, byte[] buf, int off, int len) { Mac mac = new Poly1305(); mac.init(macKey); updateRecordMAC(mac, additionalData, 0, additionalData.length); updateRecordMAC(mac, buf, off, len); byte[] output = new byte[mac.getMacSize()]; mac.doFinal(output, 0); return output; }
public static void main(String[] args) { testMac(new HMac(new SHA1Digest()), new KeyParameter(generateNonce(20)), 3); testMac(new SkeinMac(SkeinMac.SKEIN_512, 128), new KeyParameter(generateNonce(64)), 2); testMac(new SipHash(), new KeyParameter(generateNonce(16)), 1); testMac(new CMac(new AESFastEngine()), new KeyParameter(generateNonce(16)), 3); testMac(new GMac(new GCMBlockCipher(new AESFastEngine())), new ParametersWithIV(new KeyParameter( generateNonce(16)), generateNonce(16)), 5); testMac(new Poly1305(new NullEngine(16)), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); testMac(new Poly1305(new AESFastEngine()), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); testMac(new Poly1305Reference(new NullEngine(16)), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); }
private void testSequential() { // Sequential test, adapted from test-poly1305aes int len; byte[] kr = new byte[32]; byte[] m = new byte[MAXLEN]; byte[] n = new byte[16]; byte[] out = new byte[16]; int c = 0; final Mac mac = new Poly1305(new AESFastEngine()); for (int loop = 0; loop < 13; loop++) { len = 0; for (;;) { c++; mac.init(new ParametersWithIV(new KeyParameter(kr), n)); mac.update(m, 0, len); mac.doFinal(out, 0); // if (c == 678) // { // TestCase tc = CASES[0]; // // if (!Arrays.areEqual(tc.key, kr)) // { // System.err.println("Key bad"); // System.err.println(new String(Hex.encode(tc.key))); // System.err.println(new String(Hex.encode(kr))); // System.exit(1); // } // if (!Arrays.areEqual(tc.nonce, n)) // { // System.err.println("Nonce bad"); // System.exit(1); // } // System.out.printf("[%d] m: %s\n", c, new String(Hex.encode(m, 0, len))); // System.out.printf("[%d] K: %s\n", c, new String(Hex.encodje(kr))); // System.out.printf("[%d] N: %s\n", c, new String(Hex.encode(n))); // System.out.printf("[%d] M: ", c); // } // System.out.printf("%d/%s\n", c, new String(Hex.encode(out))); if (len >= MAXLEN) break; n[0] ^= loop; for (int i = 0; i < 16; ++i) n[i] ^= out[i]; if (len % 2 != 0) for (int i = 0; i < 16; ++i) kr[i] ^= out[i]; if (len % 3 != 0) for (int i = 0; i < 16; ++i) kr[i + 16] ^= out[i]; Poly1305KeyGenerator.clamp(kr); m[len++] ^= out[0]; } } // Output after 13 loops as generated by poly1305 ref if (c != 13013 || !Arrays.areEqual(out, Hex.decode("c96f60a23701a5b0fd2016f58cbe4f7e"))) { fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", new String(Hex.encode(out))); } }
private void testReset() { CipherKeyGenerator gen = new Poly1305KeyGenerator(); gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); byte[] k = gen.generateKey(); byte[] m = new byte[10000]; byte[] check = new byte[16]; byte[] out = new byte[16]; // Generate baseline Mac poly = new Poly1305(new AESFastEngine()); poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); poly.update(m, 0, m.length); poly.doFinal(check, 0); // Check reset after doFinal poly.update(m, 0, m.length); poly.doFinal(out, 0); if (!Arrays.areEqual(check, out)) { fail("Mac not reset after doFinal"); } // Check reset poly.update((byte)1); poly.update((byte)2); poly.reset(); poly.update(m, 0, m.length); poly.doFinal(out, 0); if (!Arrays.areEqual(check, out)) { fail("Mac not reset after doFinal"); } // Check init resets poly.update((byte)1); poly.update((byte)2); poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); poly.update(m, 0, m.length); poly.doFinal(out, 0); if (!Arrays.areEqual(check, out)) { fail("Mac not reset after doFinal"); } }
/** * Constructor * * @throws NoSuchAlgorithmException thrown if the given algorithm is not supported */ public BCPoly1305MacHelper() throws NoSuchAlgorithmException { this.mac = new Poly1305(); }