/** * 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 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); } }
/** * 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); } }
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"); } }
/** * Writes <code>len</code> bytes from the specified byte array starting at offset <code>off</code> * to this output stream. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception java.io.IOException if an I/O error occurs. */ public void write(byte[] b, int off, int len) throws IOException { if (bufferedBlockCipher != null) { byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)]; int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0); if (outLen != 0) { out.write(buf, 0, outLen); } } else { byte[] buf = new byte[len]; streamCipher.processBytes(b, off, len, buf, 0); out.write(buf, 0, len); } }
/** * 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(); }
/** * Writes the specified byte to this output stream. * * @param b the <code>byte</code>. * @exception java.io.IOException if an I/O error occurs. */ public void write(int b) throws IOException { oneByte[0] = (byte) b; if (bufferedBlockCipher != null) { int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0); if (len != 0) { out.write(buf, 0, len); } } else { out.write(streamCipher.returnByte((byte) b)); } }
/** Constructs a CipherOutputStream from an OutputStream and a BufferedBlockCipher. */ public CipherOutputStream(OutputStream os, BufferedBlockCipher cipher) { super(os); this.bufferedBlockCipher = cipher; this.buf = new byte[cipher.getBlockSize()]; }