private void testNullCFB() throws InvalidCipherTextException { BufferedBlockCipher b = new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)); KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); b.init(true, new ParametersWithIV(kp, new byte[16])); byte[] out = new byte[b.getOutputSize(tData.length)]; int len = b.processBytes(tData, 0, tData.length, out, 0); len += b.doFinal(out, len); if (!areEqual(outCFB1, out)) { fail("no match on first nullCFB check"); } b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); len = b.processBytes(tData, 0, tData.length, out, 0); len += b.doFinal(out, len); if (!areEqual(outCFB2, out)) { fail("no match on second nullCFB check"); } }
/** * Decrypt bytes previously encrypted with this class. * * @param bytesToDecode The bytes to decrypt * @param passwordbThe password to use for decryption * @return The decrypted bytes * @throws IOException */ private static byte[] decryptRaw(final byte[] bytesToDecode, final char[] password) throws IOException { try { // separate the salt and bytes to decrypt final byte[] salt = new byte[SALT_LENGTH]; System.arraycopy(bytesToDecode, 0, salt, 0, SALT_LENGTH); final byte[] cipherBytes = new byte[bytesToDecode.length - SALT_LENGTH]; System.arraycopy( bytesToDecode, SALT_LENGTH, cipherBytes, 0, bytesToDecode.length - SALT_LENGTH); final ParametersWithIV key = (ParametersWithIV) getAESPasswordKey(password, salt); // decrypt the message final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine())); cipher.init(false, key); final byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)]; final int processLen = cipher.processBytes(cipherBytes, 0, cipherBytes.length, decryptedBytes, 0); final int doFinalLen = cipher.doFinal(decryptedBytes, processLen); return Arrays.copyOf(decryptedBytes, processLen + doFinalLen); } catch (final InvalidCipherTextException x) { throw new IOException("Could not decrypt bytes", x); } catch (final DataLengthException x) { throw new IOException("Could not decrypt bytes", x); } }
/** * Password based encryption using AES - CBC 256 bits. * * @param plainBytes The bytes to encrypt * @param password The password to use for encryption * @return SALT_LENGTH bytes of salt followed by the encrypted bytes. * @throws IOException */ private static byte[] encryptRaw(final byte[] plainTextAsBytes, final char[] password) throws IOException { try { // Generate salt - each encryption call has a different salt. final byte[] salt = new byte[SALT_LENGTH]; secureRandom.nextBytes(salt); final ParametersWithIV key = (ParametersWithIV) getAESPasswordKey(password, salt); // The following code uses an AES cipher to encrypt the message. final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine())); cipher.init(true, key); final byte[] encryptedBytes = new byte[cipher.getOutputSize(plainTextAsBytes.length)]; final int processLen = cipher.processBytes(plainTextAsBytes, 0, plainTextAsBytes.length, encryptedBytes, 0); final int doFinalLen = cipher.doFinal(encryptedBytes, processLen); // The result bytes are the SALT_LENGTH bytes followed by the encrypted bytes. return concat(salt, Arrays.copyOf(encryptedBytes, processLen + doFinalLen)); } catch (final InvalidCipherTextException x) { throw new IOException("Could not encrypt bytes", x); } catch (final DataLengthException x) { throw new IOException("Could not encrypt bytes", x); } }
/** * Decrypt bytes previously encrypted with this class. * * @param bytesToDecode The bytes to decrypt * @param passwordbThe password to use for decryption * @return The decrypted bytes * @throws EncrypterDecrypterException */ public byte[] decrypt(byte[] bytesToDecode, CharSequence password) throws KeyCrypterException { try { // separate the salt and bytes to decrypt byte[] salt = new byte[SALT_LENGTH]; System.arraycopy(bytesToDecode, 0, salt, 0, SALT_LENGTH); byte[] cipherBytes = new byte[bytesToDecode.length - SALT_LENGTH]; System.arraycopy( bytesToDecode, SALT_LENGTH, cipherBytes, 0, bytesToDecode.length - SALT_LENGTH); ParametersWithIV key = (ParametersWithIV) getAESPasswordKey(password, salt); // decrypt the message BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine())); cipher.init(false, key); byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)]; int length = cipher.processBytes(cipherBytes, 0, cipherBytes.length, decryptedBytes, 0); cipher.doFinal(decryptedBytes, length); return decryptedBytes; } catch (Exception e) { throw new KeyCrypterException("Could not decrypt input string", e); } }
/** * Password based encryption using AES - CBC 256 bits. * * @param plainBytes The bytes to encrypt * @param password The password to use for encryption * @return SALT_LENGTH bytes of salt followed by the encrypted bytes. * @throws EncrypterDecrypterException */ public byte[] encrypt(byte[] plainTextAsBytes, CharSequence password) throws KeyCrypterException { try { // Generate salt - each encryption call has a different salt. byte[] salt = new byte[SALT_LENGTH]; secureRandom.nextBytes(salt); ParametersWithIV key = (ParametersWithIV) getAESPasswordKey(password, salt); // The following code uses an AES cipher to encrypt the message. BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine())); cipher.init(true, key); byte[] encryptedBytes = new byte[cipher.getOutputSize(plainTextAsBytes.length)]; int length = cipher.processBytes(plainTextAsBytes, 0, plainTextAsBytes.length, encryptedBytes, 0); cipher.doFinal(encryptedBytes, length); // The result bytes are the SALT_LENGTH bytes followed by the encrypted bytes. return concat(salt, encryptedBytes); } catch (Exception e) { throw new KeyCrypterException( "Could not encrypt bytes '" + Utils.bytesToHexString(plainTextAsBytes) + "'", e); } }
/** * Closes this output stream and releases any system resources associated with this stream. * * <p>This method invokes the <code>doFinal</code> method of the encapsulated cipher object, which * causes any bytes buffered by the encapsulated cipher to be processed. The result is written out * by calling the <code>flush</code> method of this output stream. * * <p>This method resets the encapsulated cipher object to its initial state and calls the <code> * close</code> method of the underlying output stream. * * @exception java.io.IOException if an I/O error occurs. */ public void close() throws IOException { try { if (bufferedBlockCipher != null) { byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)]; int outLen = bufferedBlockCipher.doFinal(buf, 0); if (outLen != 0) { out.write(buf, 0, outLen); } } } catch (Exception e) { throw new IOException("Error closing stream: " + e.toString()); } flush(); super.close(); }