Java tutorial
/* * Copyright 2015 dorkbox, llc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dorkbox.util.crypto; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.SecureRandom; import java.util.Arrays; import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.junit.Test; public class AesTest { org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass()); private static String entropySeed = "asdjhasdkljalksdfhlaks4356268909087s0dfgkjh255124515hasdg87"; @Test public void AesGcm() throws IOException { byte[] bytes = "hello, my name is inigo montoya".getBytes(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); GCMBlockCipher aesEngine = new GCMBlockCipher(new AESFastEngine()); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key (32 bytes) rand.nextBytes(iv); // 128bit block size (16 bytes) byte[] encryptAES = CryptoAES.encrypt(aesEngine, key, iv, bytes, logger); byte[] decryptAES = CryptoAES.decrypt(aesEngine, key, iv, encryptAES, logger); if (Arrays.equals(bytes, encryptAES)) { fail("bytes should not be equal"); } if (!Arrays.equals(bytes, decryptAES)) { fail("bytes not equal"); } } // Note: this is still tested, but DO NOT USE BLOCK MODE as it does NOT provide authentication. GCM does. @SuppressWarnings("deprecation") @Test public void AesBlock() throws IOException { byte[] bytes = "hello, my name is inigo montoya".getBytes(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); PaddedBufferedBlockCipher aesEngine = new PaddedBufferedBlockCipher( new CBCBlockCipher(new AESFastEngine())); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key rand.nextBytes(iv); // 16bit block size byte[] encryptAES = CryptoAES.encrypt(aesEngine, key, iv, bytes, logger); byte[] decryptAES = CryptoAES.decrypt(aesEngine, key, iv, encryptAES, logger); if (Arrays.equals(bytes, encryptAES)) { fail("bytes should not be equal"); } if (!Arrays.equals(bytes, decryptAES)) { fail("bytes not equal"); } } @Test public void AesGcmStream() throws IOException { byte[] originalBytes = "hello, my name is inigo montoya".getBytes(); ByteArrayInputStream inputStream = new ByteArrayInputStream(originalBytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); GCMBlockCipher aesEngine = new GCMBlockCipher(new AESFastEngine()); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key rand.nextBytes(iv); // 128bit block size boolean success = CryptoAES.encryptStream(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] encryptBytes = outputStream.toByteArray(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); outputStream = new ByteArrayOutputStream(); success = CryptoAES.decryptStream(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] decryptBytes = outputStream.toByteArray(); if (Arrays.equals(originalBytes, encryptBytes)) { fail("bytes should not be equal"); } if (!Arrays.equals(originalBytes, decryptBytes)) { fail("bytes not equal"); } } // Note: this is still tested, but DO NOT USE BLOCK MODE as it does NOT provide authentication. GCM does. @SuppressWarnings("deprecation") @Test public void AesBlockStream() throws IOException { byte[] originalBytes = "hello, my name is inigo montoya".getBytes(); ByteArrayInputStream inputStream = new ByteArrayInputStream(originalBytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); PaddedBufferedBlockCipher aesEngine = new PaddedBufferedBlockCipher( new CBCBlockCipher(new AESFastEngine())); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key rand.nextBytes(iv); // 128bit block size boolean success = CryptoAES.encryptStream(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] encryptBytes = outputStream.toByteArray(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); outputStream = new ByteArrayOutputStream(); success = CryptoAES.decryptStream(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] decryptBytes = outputStream.toByteArray(); if (Arrays.equals(originalBytes, encryptBytes)) { fail("bytes should not be equal"); } if (!Arrays.equals(originalBytes, decryptBytes)) { fail("bytes not equal"); } } @Test public void AesWithIVGcm() throws IOException { byte[] bytes = "hello, my name is inigo montoya".getBytes(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); GCMBlockCipher aesEngine = new GCMBlockCipher(new AESFastEngine()); byte[] key = new byte[32]; // 256bit key byte[] iv = new byte[aesEngine.getUnderlyingCipher().getBlockSize()]; // note: the IV needs to be VERY unique! rand.nextBytes(key); rand.nextBytes(iv); byte[] encryptAES = CryptoAES.encryptWithIV(aesEngine, key, iv, bytes, logger); byte[] decryptAES = CryptoAES.decryptWithIV(aesEngine, key, encryptAES, logger); if (Arrays.equals(bytes, encryptAES)) { fail("bytes should not be equal"); } if (!Arrays.equals(bytes, decryptAES)) { fail("bytes not equal"); } } // Note: this is still tested, but DO NOT USE BLOCK MODE as it does NOT provide authentication. GCM does. @SuppressWarnings("deprecation") @Test public void AesWithIVBlock() throws IOException { byte[] bytes = "hello, my name is inigo montoya".getBytes(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); PaddedBufferedBlockCipher aesEngine = new PaddedBufferedBlockCipher( new CBCBlockCipher(new AESFastEngine())); byte[] key = new byte[32]; // 256bit key byte[] iv = new byte[aesEngine.getUnderlyingCipher().getBlockSize()]; // note: the IV needs to be VERY unique! rand.nextBytes(key); rand.nextBytes(iv); byte[] encryptAES = CryptoAES.encryptWithIV(aesEngine, key, iv, bytes, logger); byte[] decryptAES = CryptoAES.decryptWithIV(aesEngine, key, encryptAES, logger); if (Arrays.equals(bytes, encryptAES)) { fail("bytes should not be equal"); } if (!Arrays.equals(bytes, decryptAES)) { fail("bytes not equal"); } } @Test public void AesWithIVGcmStream() throws IOException { byte[] originalBytes = "hello, my name is inigo montoya".getBytes(); ByteArrayInputStream inputStream = new ByteArrayInputStream(originalBytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); GCMBlockCipher aesEngine = new GCMBlockCipher(new AESFastEngine()); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key rand.nextBytes(iv); // 128bit block size boolean success = CryptoAES.encryptStreamWithIV(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] encryptBytes = outputStream.toByteArray(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); outputStream = new ByteArrayOutputStream(); success = CryptoAES.decryptStreamWithIV(aesEngine, key, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] decryptBytes = outputStream.toByteArray(); if (Arrays.equals(originalBytes, encryptBytes)) { fail("bytes should not be equal"); } if (!Arrays.equals(originalBytes, decryptBytes)) { fail("bytes not equal"); } } // Note: this is still tested, but DO NOT USE BLOCK MODE as it does NOT provide authentication. GCM does. @SuppressWarnings("deprecation") @Test public void AesWithIVBlockStream() throws IOException { byte[] originalBytes = "hello, my name is inigo montoya".getBytes(); ByteArrayInputStream inputStream = new ByteArrayInputStream(originalBytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); SecureRandom rand = new SecureRandom(entropySeed.getBytes()); PaddedBufferedBlockCipher aesEngine = new PaddedBufferedBlockCipher( new CBCBlockCipher(new AESFastEngine())); byte[] key = new byte[32]; byte[] iv = new byte[16]; // note: the IV needs to be VERY unique! rand.nextBytes(key); // 256bit key rand.nextBytes(iv); // 128bit block size boolean success = CryptoAES.encryptStreamWithIV(aesEngine, key, iv, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] encryptBytes = outputStream.toByteArray(); inputStream = new ByteArrayInputStream(outputStream.toByteArray()); outputStream = new ByteArrayOutputStream(); success = CryptoAES.decryptStreamWithIV(aesEngine, key, inputStream, outputStream, logger); if (!success) { fail("crypto was not successful"); } byte[] decryptBytes = outputStream.toByteArray(); if (Arrays.equals(originalBytes, encryptBytes)) { fail("bytes should not be equal"); } if (!Arrays.equals(originalBytes, decryptBytes)) { fail("bytes not equal"); } } }