HKDF
CBC Cipher
GCM Cipher
import java.security.SecureRandom; import org.apache.commons.codec.digest.HmacUtils; public class HKDF { static int HMAC_LENGTH = 32;//in bytes static byte[][] HKDF_extract(byte[] xts,byte[] skm){ byte[][] PRK = new byte[2][]; if(xts == null){ byte[] saltPRK = new byte[HMAC_LENGTH]; PRK[0] = saltPRK; new SecureRandom().nextBytes(saltPRK); PRK[1] = HmacUtils.hmacSha256(saltPRK,skm); return PRK; } PRK[0] = xts; PRK[1] = HmacUtils.hmacSha256(xts,skm); return PRK; } static byte[] HKDF_expand(byte[] prk,byte[] km,int t){ byte[] K = new byte[t*HMAC_LENGTH];//for holding all keys byte[] Ki = km;//key from previous interation for(int i=0;i
0) System.arraycopy(Ki,0,info,0,Ki.length); Ki = HmacUtils.hmacSha256(prk,info);//generate new key //expand System.arraycopy(Ki,0,K,Ki.length*i,Ki.length); } return K; } public static byte[][] deriveKeys(byte[] salt,byte[] SKM,int[] keySizes){ byte[][] PRK = HKDF_extract(salt,SKM);//extract PRF //sum up the individual key sizes to get total key length needed int KEY_LENGTH = keySizes[0]; for(int i=1;i
import java.io.UnsupportedEncodingException; import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.beanutils.LazyDynaBean; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.HmacUtils; public class CBC_Cipher { static Object crud; static Object HKDF; public CBC_Cipher(Object crud){ CBC_Cipher.crud = crud; HKDF = crud.call("../test/keygen/hkdf.ste");//get HKDF implementation } public CBC_Cipher(){ } static int HMAC_LENGTH = 32;//in bytes static int HALF_HMAC_LENGTH = 16;//in bytes static int IV_LENGTH = 16;//in bytes static String PADDING = "PKCS5Padding";//same as PKCS7Padding public static byte[] encrypt(byte[] src,byte[] secret,int keySize) { int[] KEY_SIZES = new int[2];KEY_SIZES[0] = keySize;KEY_SIZES[1] = keySize; Cipher cipher = Cipher.getInstance("AES/CBC/"+PADDING); SecureRandom random = new SecureRandom(); byte[] byteIV = new byte[IV_LENGTH]; random.nextBytes(byteIV);//generate initialization vector (iv) //derive encryption and HMAC keys from secret key using HKDF byte[][] keys = HKDF.deriveKeys(null,secret,KEY_SIZES); byte[] saltPRK = keys[0],KEYe = keys[1],KEYm = keys[2]; Key eKey = new SecretKeySpec(KEYe,"AES"); IvParameterSpec iv = new IvParameterSpec(byteIV); cipher.init(Cipher.ENCRYPT_MODE, eKey, iv); byte[] cText = cipher.doFinal(src); byte[] hmac = HmacUtils.hmacSha256(KEYm,cText); byte[] cTextPlusMAC = new byte[hmac.length+cText.length]; System.arraycopy(cText,0,cTextPlusMAC,0,cText.length); System.arraycopy(hmac,0,cTextPlusMAC,cText.length,hmac.length);//cipher text+hmac byte[] output = new byte[saltPRK.length+byteIV.length+cTextPlusMAC.length]; System.arraycopy(saltPRK,0,output,0,saltPRK.length);//+PRK salt System.arraycopy(byteIV,0,output,saltPRK.length,byteIV.length);//+iv System.arraycopy(cTextPlusMAC,0,output,saltPRK.length+byteIV.length,cTextPlusMAC.length);//+cipher text+hmac return output; } public static byte[] decrypt(byte[] src, byte[] secret,int keySize) { int[] KEY_SIZES = new int[2];KEY_SIZES[0] = keySize;KEY_SIZES[1] = keySize; Cipher cipher = Cipher.getInstance("AES/CBC/"+PADDING); byte[] saltPRK = new byte[HMAC_LENGTH]; System.arraycopy(src,0,saltPRK,0,saltPRK.length); byte[] byteIV = new byte[IV_LENGTH]; System.arraycopy(src,saltPRK.length,byteIV,0,byteIV.length); byte[][] keys = HKDF.deriveKeys(saltPRK,secret,KEY_SIZES); byte[] KEYe = keys[1],KEYm = keys[2]; Key eKey = new SecretKeySpec(KEYe,"AES"); IvParameterSpec iv = new IvParameterSpec(byteIV); cipher.init(Cipher.DECRYPT_MODE, eKey, iv); byte[] cText = new byte[src.length-byteIV.length-saltPRK.length-HMAC_LENGTH]; //extract cipher text bytes System.arraycopy(src,saltPRK.length+byteIV.length,cText,0,src.length-byteIV.length-saltPRK.length-HMAC_LENGTH); byte[] in_hmac = new byte[HMAC_LENGTH]; //extract hmac bytes System.arraycopy(src,saltPRK.length+byteIV.length+cText.length,in_hmac,0,HMAC_LENGTH); //create hmac of received cipher text byte[] hmac = HmacUtils.hmacSha256(KEYm,cText); if(java.util.Arrays.equals(in_hmac,hmac)){//authenticate MAC byte[] plaintext = cipher.doFinal(cText); return plaintext; } else { CBC_Cipher.crud.logger().error("HMAC authentication failed:("+new String(in_hmac)+","+new String(hmac)+")"); } return null; } } return new CBC_Cipher(crud);
import javax.crypto.*; import javax.crypto.spec.GCMParameterSpec; import java.security.Key; import java.nio.ByteBuffer; import java.security.SecureRandom; import javax.crypto.spec.SecretKeySpec; import java.util.Arrays; import org.apache.commons.beanutils.LazyDynaBean; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.HmacUtils; public class GCM_Cipher { // AES-GCM parameters public static final int GCM_NONCE_LENGTH = 12; // in bytes public static final int GCM_TAG_LENGTH = 16; // in bytes public static final String PADDING = "NoPadding"; static Object HKDF; static int HMAC_LENGTH = 32;//in bytes static int HALF_HMAC_LENGTH = 16;//in bytes public GCM_Cipher(Object crud) { HKDF = crud.call("../test/keygen/hkdf.ste");//get HKDF implementation } public GCM_Cipher() { } public static byte[] encrypt(byte[] input, byte[] secret, int keySize){ int[] KEY_SIZES = new int[2];KEY_SIZES[0] = keySize;KEY_SIZES[1] = keySize; // Encrypt Cipher cipher = Cipher.getInstance("AES/GCM/"+PADDING, "SunJCE"); SecureRandom random = new SecureRandom(); final byte[] nonce = new byte[GCM_NONCE_LENGTH]; random.nextBytes(nonce); //derive encryption and HMAC keys from secret key using HKDF byte[][] keys = HKDF.deriveKeys(null,secret,KEY_SIZES); byte[] saltPRK = keys[0],KEYe = keys[1];//salt used to generate PRK Key eKey = new SecretKeySpec(KEYe,"AES"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce); cipher.init(Cipher.ENCRYPT_MODE, eKey, spec); byte[] cText = cipher.doFinal(input);//cipher text + authentication tag byte[] output = new byte[saltPRK.length+nonce.length+cText.length]; System.arraycopy(saltPRK,0,output,0,saltPRK.length);//+PRK salt System.arraycopy(nonce,0,output,saltPRK.length,nonce.length);//+nonce System.arraycopy(cText,0,output,saltPRK.length+nonce.length,cText.length);//+cipher text + authentication tag return output; } public static byte[] decrypt(byte[] input, byte[] secret,int keySize){ int[] KEY_SIZES = new int[2];KEY_SIZES[0] = keySize;KEY_SIZES[1] = keySize; // decrypt Cipher cipher = Cipher.getInstance("AES/GCM/"+PADDING, "SunJCE"); byte[] saltPRK = new byte[HMAC_LENGTH]; System.arraycopy(input,0,saltPRK,0,saltPRK.length);//extract salt for generating PRK final byte[] nonce = new byte[GCM_NONCE_LENGTH]; System.arraycopy(input,saltPRK.length,nonce,0,nonce.length); byte[][] keys = HKDF.deriveKeys(saltPRK,secret,KEY_SIZES);//derive necessary keys byte[] KEYe = keys[1]; Key eKey = new SecretKeySpec(KEYe,"AES"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce); cipher.init(Cipher.DECRYPT_MODE, eKey, spec); byte[] cText = new byte[input.length-saltPRK.length-nonce.length]; //extract cipher text + authentication tag System.arraycopy(input,saltPRK.length+nonce.length,cText,0,input.length-saltPRK.length-nonce.length); byte[] uncipherText = cipher.doFinal(cText); return uncipherText; } } return new GCM_Cipher(crud);