Java crypto library:
Example:
Crypto _c = new Crypto(); Crypto.AES aes = _c .new AES(); int keySizeInBits = 128; int keySizeInBytes = keySizeInBits/8; // Derive a cryptographic key: PBKDF2 String salt = Utils.byteArrayToHexString(Utils.getRandomBytes(8)); String key = Utils.pbkdf2("Secret Passphrase", salt, 1000, keySizeInBytes); // generate IV byte[] ivBytes = aes.generateIV(); aes.setIV(ivBytes); /*** encrypt */ String ciphertext = aes.encrypt("plaintext", key); /*** decrypt */ String plaintext = aes.decrypt(ciphertext, key);
Example JCrypto: JCrypto.jar
Library:
package it.polito.ai; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidParameterSpecException; import java.security.spec.RSAPublicKeySpec; import java.util.regex.Pattern; import java.util.Random; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.nio.charset.Charset; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class Crypto { /* * AES */ public class AES { private final String ALGORITHM = "AES"; // symmetric algorithm for data encryption private final String MODE = "CBC"; private final String PADDING = "PKCS5Padding"; // Padding for symmetric algorithm private final String CIPHER_TRANSFORMATION = ALGORITHM + "/" + MODE + "/" + PADDING; private Charset PLAIN_TEXT_ENCODING = Charset.forName("UTF-8"); // character encoding //private final String CRYPTO_PROVIDER = "SunMSCAPI"; // provider for the crypto private int KEY_SIZE_BITS = 128; /* symmetric key size (128, 192, 256) * if using 256 you must have the Java Cryptography Extension (JCE) * Unlimited Strength Jurisdiction Policy Files installed */ private int KEY_SIZE_BYTES = KEY_SIZE_BITS/8; private Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION); private byte[] ivBytes = new byte[KEY_SIZE_BYTES]; private SecretKey key; public AES() throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException, InvalidParameterSpecException, InvalidKeyException, InvalidAlgorithmParameterException { KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM); kgen.init(KEY_SIZE_BITS); key = kgen.generateKey(); cipher.init(Cipher.ENCRYPT_MODE, key); ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); } public String getIVAsHex() { return Utils.byteArrayToHexString(ivBytes); } public String getKeyAsHex() { return Utils.byteArrayToHexString(key.getEncoded()); } public void setStringToKey(String keyText) throws NoSuchAlgorithmException, UnsupportedEncodingException { setKey(keyText.getBytes()); } public void setHexToKey(String hexKey) { setKey(Utils.hexStringToByteArray(hexKey)); } public void setKey(byte[] bArray) { byte[] bText = new byte[KEY_SIZE_BYTES]; int end = Math.min(KEY_SIZE_BYTES, bArray.length); System.arraycopy(bArray, 0, bText, 0, end); key = new SecretKeySpec(bText, ALGORITHM); } public void setStringToIV(String ivText) { setIV(ivText.getBytes()); } public void setHexToIV(String hexIV) { setIV(Utils.hexStringToByteArray(hexIV)); } public void setIV(byte[] bArray) { byte[] bText = new byte[KEY_SIZE_BYTES]; int end = Math.min(KEY_SIZE_BYTES, bArray.length); System.arraycopy(bArray, 0, bText, 0, end); ivBytes = bText; } public byte[] generateIV() { byte[] iv = Utils.getRandomBytes(KEY_SIZE_BYTES); return iv; } public String encrypt(String plaintext, String passphrase) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { if (plaintext.length() == 0) return null; setStringToKey(passphrase); cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes)); byte[] encrypted = cipher.doFinal(plaintext.getBytes(PLAIN_TEXT_ENCODING)); return Utils.byteArrayToBase64String(encrypted); } public String decrypt(String ciphertext, String passphrase) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { if (ciphertext.length() == 0) return null; setStringToKey(passphrase); byte[] dec = Utils.base64StringToByteArray(ciphertext); cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivBytes)); byte[] decrypted = cipher.doFinal(dec); return new String(decrypted, PLAIN_TEXT_ENCODING); } } /* * PBKDF2: deriveKey */ private static class PBKDF2 { private static byte[] deriveKey(byte[] password, byte[] salt, int iterationCount, int dkLen) throws NoSuchAlgorithmException, InvalidKeyException { SecretKeySpec keyspec = new SecretKeySpec(password, "HmacSHA256"); Mac prf = Mac.getInstance("HmacSHA256"); prf.init( keyspec ); // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for // variables and functions in this day and age, but they // reflect the terse symbols used in RFC 2898 to describe // the PBKDF2 algorithm, which improves validation of the // code vs. the RFC. // // dklen is expressed in bytes. (16 for a 128-bit key) int hLen = prf.getMacLength(); // 20 for SHA1 int l = Math.max(dkLen, hLen); // 1 for 128bit (16-byte) keys int r = dkLen - (l-1)*hLen; // 16 for 128bit (16-byte) keys byte T[] = new byte[l * hLen]; int ti_offset = 0; for (int i = 1; i <= l; i++) { F(T, ti_offset, prf, salt, iterationCount, i); ti_offset += hLen; } if (r < hLen) { // Incomplete last block byte DK[] = new byte[dkLen]; System.arraycopy(T, 0, DK, 0, dkLen); return DK; } return T; } private static void F(byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex) { final int hLen = prf.getMacLength(); byte U_r[] = new byte[ hLen ]; // U0 = S || INT (i); byte U_i[] = new byte[S.length + 4]; System.arraycopy(S, 0, U_i, 0, S.length); INT(U_i, S.length, blockIndex); for(int i = 0; i < c; i++) { U_i = prf.doFinal(U_i); xor( U_r, U_i ); } System.arraycopy(U_r, 0, dest, offset, hLen); } private static void xor(byte[] dest, byte[] src) { for(int i = 0; i < dest.length; i++) { dest[i] ^= src[i]; } } private static void INT(byte[] dest, int offset, int i) { dest[offset + 0] = (byte) (i / (256 * 256 * 256)); dest[offset + 1] = (byte) (i / (256 * 256)); dest[offset + 2] = (byte) (i / (256)); dest[offset + 3] = (byte) (i); } // Costructor private PBKDF2 () {} } /* * HASH */ public class HASH { public String MD2(String message) throws NoSuchAlgorithmException { MessageDigest md2 = MessageDigest.getInstance("MD2"); byte[] array = md2.digest(message.getBytes()); return arrayToString(array); } public String MD5(String message) throws NoSuchAlgorithmException { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] array = md5.digest(message.getBytes()); return arrayToString(array); } public String SHA1(String message) throws NoSuchAlgorithmException { MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); byte[] array = sha1.digest(message.getBytes()); return arrayToString(array); } public String SHA256(String message) throws NoSuchAlgorithmException { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); byte[] array = sha256.digest(message.getBytes()); return arrayToString(array); } public String SHA384(String message) throws NoSuchAlgorithmException { MessageDigest sha384 = MessageDigest.getInstance("SHA-384"); byte[] array = sha384.digest(message.getBytes()); return arrayToString(array); } public String SHA512(String message) throws NoSuchAlgorithmException { MessageDigest sha512 = MessageDigest.getInstance("SHA-512"); byte[] array = sha512.digest(message.getBytes()); return arrayToString(array); } private String arrayToString(byte[] array) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < array.length; ++i) { sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3)); } return sb.toString(); } } /* * RSA */ public class RSA { private Charset PLAIN_TEXT_ENCODING = Charset.forName("UTF-8"); private int KEY_SIZE_BITS = 1024; private Key publicKey; private Key privateKey; private BigInteger modulus; private BigInteger exponent; Cipher cipher; KeyFactory fact; public RSA() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException { cipher = Cipher.getInstance("RSA"); fact = KeyFactory.getInstance("RSA"); setNewKey(KEY_SIZE_BITS); } public boolean setNewKey(int KeySize) throws NoSuchAlgorithmException, InvalidKeySpecException { if (KeySize <= 0) return false; KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(KeySize); KeyPair kp = kpg.genKeyPair(); publicKey = kp.getPublic(); privateKey = kp.getPrivate(); RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey, RSAPublicKeySpec.class); modulus = pub.getModulus(); exponent = pub.getPublicExponent(); return true; } public BigInteger getModulus() { return modulus; } public BigInteger getExponent() { return exponent; } public Key getPublicKey() { return publicKey; } public Key getPrivateKey() { return privateKey; } public String encrypt(String plaintext) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException { if (plaintext.length() == 0) return null; cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encrypted = cipher.doFinal(plaintext.getBytes()); return Utils.byteArrayToBase64String(encrypted); } public String decrypt(String ciphertext) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException { if (ciphertext.length() == 0) return null; byte[] dec = Utils.base64StringToByteArray(ciphertext); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decrypted = cipher.doFinal(dec); return new String(decrypted, PLAIN_TEXT_ENCODING); } } /* * Utils */ public static class Utils { public static String pbkdf2(String password, String salt, int iterationCount, int dkLen) throws InvalidKeyException, NoSuchAlgorithmException { if (dkLen!=16 && dkLen!=24 && dkLen!=32) { dkLen=16; } if (iterationCount<0) { iterationCount=0; } byte[] _password = password.getBytes(); byte[] _salt = salt.getBytes(); byte[] key = PBKDF2.deriveKey(_password, _salt, iterationCount, dkLen); return new String(key); } public static byte[] getRandomBytes(int len) { if(len<0) { len=8; } Random ranGen = new SecureRandom(); byte[] aesKey = new byte[len]; ranGen.nextBytes(aesKey); return aesKey; } public static String byteArrayToHexString(byte[] raw) { StringBuilder sb = new StringBuilder(2 + raw.length * 2); sb.append("0x"); for (int i = 0; i < raw.length; i++) { sb.append(String.format("%02X", Integer.valueOf(raw[i] & 0xFF))); } return sb.toString(); } public static byte[] hexStringToByteArray(String hex) { Pattern replace = Pattern.compile("^0x"); String s = replace.matcher(hex).replaceAll(""); byte[] b = new byte[s.length() / 2]; for (int i = 0; i < b.length; i++){ int index = i * 2; int v = Integer.parseInt(s.substring(index, index + 2), 16); b[i] = (byte)v; } return b; } public static String byteArrayToBase64String(byte[] raw) { return new String(Base64Coder.encode(raw)); } public static byte[] base64StringToByteArray(String str) { return Base64Coder.decode(str); } public static String base64_encode(String str) { return Base64Coder.encodeString(str); } public static String base64_decode(String str) { return Base64Coder.decodeString(str); } } /* * Base64Coder */ private static class Base64Coder { // The line separator string of the operating system. private static final String systemLineSeparator = System.getProperty("line.separator"); // Mapping table from 6-bit nibbles to Base64 characters. private static final char[] map1 = new char[64]; static { int i=0; for (char c='A'; c<='Z'; c++) map1[i++] = c; for (char c='a'; c<='z'; c++) map1[i++] = c; for (char c='0'; c<='9'; c++) map1[i++] = c; map1[i++] = '+'; map1[i++] = '/'; } // Mapping table from Base64 characters to 6-bit nibbles. private static final byte[] map2 = new byte[128]; static { for (int i=0; i<map2.length; i++) map2[i] = -1; for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } /** * Encodes a string into Base64 format. * No blanks or line breaks are inserted. * @param s A String to be encoded. * @return A String containing the Base64 encoded data. */ public static String encodeString (String s) { return new String(encode(s.getBytes())); } /** * Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters. * This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>. * @param in An array containing the data bytes to be encoded. * @return A String containing the Base64 encoded data, broken into lines. */ public static String encodeLines (byte[] in) { return encodeLines(in, 0, in.length, 76, systemLineSeparator); } /** * Encodes a byte array into Base 64 format and breaks the output into lines. * @param in An array containing the data bytes to be encoded. * @param iOff Offset of the first byte in <code>in</code> to be processed. * @param iLen Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>. * @param lineLen Line length for the output data. Should be a multiple of 4. * @param lineSeparator The line separator to be used to separate the output lines. * @return A String containing the Base64 encoded data, broken into lines. */ public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator) { int blockLen = (lineLen*3) / 4; if (blockLen <= 0) throw new IllegalArgumentException(); int lines = (iLen+blockLen-1) / blockLen; int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length(); StringBuilder buf = new StringBuilder(bufLen); int ip = 0; while (ip < iLen) { int l = Math.min(iLen-ip, blockLen); buf.append (encode(in, iOff+ip, l)); buf.append (lineSeparator); ip += l; } return buf.toString(); } /** * Encodes a byte array into Base64 format. * No blanks or line breaks are inserted in the output. * @param in An array containing the data bytes to be encoded. * @return A character array containing the Base64 encoded data. */ public static char[] encode (byte[] in) { return encode(in, 0, in.length); } /** * Encodes a byte array into Base64 format. * No blanks or line breaks are inserted in the output. * @param in An array containing the data bytes to be encoded. * @param iLen Number of bytes to process in <code>in</code>. * @return A character array containing the Base64 encoded data. */ public static char[] encode (byte[] in, int iLen) { return encode(in, 0, iLen); } /** * Encodes a byte array into Base64 format. * No blanks or line breaks are inserted in the output. * @param in An array containing the data bytes to be encoded. * @param iOff Offset of the first byte in <code>in</code> to be processed. * @param iLen Number of bytes to process in <code>in</code>, starting at <code>iOff</code>. * @return A character array containing the Base64 encoded data. */ public static char[] encode (byte[] in, int iOff, int iLen) { int oDataLen = (iLen*4+2)/3; // output length without padding int oLen = ((iLen+2)/3)*4; // output length including padding char[] out = new char[oLen]; int ip = iOff; int iEnd = iOff + iLen; int op = 0; while (ip < iEnd) { int i0 = in[ip++] & 0xff; int i1 = ip < iEnd ? in[ip++] & 0xff : 0; int i2 = ip < iEnd ? in[ip++] & 0xff : 0; int o0 = i0 >>> 2; int o1 = ((i0 & 3) << 4) | (i1 >>> 4); int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); int o3 = i2 & 0x3F; out[op++] = map1[o0]; out[op++] = map1[o1]; out[op] = op < oDataLen ? map1[o2] : '='; op++; out[op] = op < oDataLen ? map1[o3] : '='; op++; } return out; } /** * Decodes a string from Base64 format. * No blanks or line breaks are allowed within the Base64 encoded input data. * @param s A Base64 String to be decoded. * @return A String containing the decoded data. * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ public static String decodeString (String s) { return new String(decode(s)); } /** * Decodes a byte array from Base64 format and ignores line separators, tabs and blanks. * CR, LF, Tab and Space characters are ignored in the input data. * This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>. * @param s A Base64 String to be decoded. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ public static byte[] decodeLines (String s) { char[] buf = new char[s.length()]; int p = 0; for (int ip = 0; ip < s.length(); ip++) { char c = s.charAt(ip); if (c != ' ' && c != '\r' && c != '\n' && c != '\t') buf[p++] = c; } return decode(buf, 0, p); } /** * Decodes a byte array from Base64 format. * No blanks or line breaks are allowed within the Base64 encoded input data. * @param s A Base64 String to be decoded. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ public static byte[] decode (String s) { return decode(s.toCharArray()); } /** * Decodes a byte array from Base64 format. * No blanks or line breaks are allowed within the Base64 encoded input data. * @param in A character array containing the Base64 encoded data. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ public static byte[] decode (char[] in) { return decode(in, 0, in.length); } /** * Decodes a byte array from Base64 format. * No blanks or line breaks are allowed within the Base64 encoded input data. * @param in A character array containing the Base64 encoded data. * @param iOff Offset of the first character in <code>in</code> to be processed. * @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ public static byte[] decode (char[] in, int iOff, int iLen) { if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--; int oLen = (iLen*3) / 4; byte[] out = new byte[oLen]; int ip = iOff; int iEnd = iOff + iLen; int op = 0; while (ip < iEnd) { int i0 = in[ip++]; int i1 = in[ip++]; int i2 = ip < iEnd ? in[ip++] : 'A'; int i3 = ip < iEnd ? in[ip++] : 'A'; if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); int b0 = map2[i0]; int b1 = map2[i1]; int b2 = map2[i2]; int b3 = map2[i3]; if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); int o0 = ( b0 <<2) | (b1>>>4); int o1 = ((b1 & 0xf)<<4) | (b2>>>2); int o2 = ((b2 & 3)<<6) | b3; out[op++] = (byte)o0; if (op<oLen) out[op++] = (byte)o1; if (op<oLen) out[op++] = (byte)o2; } return out; } // Dummy constructor. private Base64Coder() {} } }
The modes of operation currently available are:
- OFB
- CBC
- CFB
- CTR