Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.parelon.pskc; import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException; import com.sun.org.apache.xml.internal.security.utils.Base64; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; /** * This class handles all the operation regarding both AES encryption/decryption * and HMAC-SHA1 signature. * * @author Vincenzo Abate * @author Marco Di Carlo */ public class CryptManager { private String privateKeyBytes, publicKeyBytes, aesKeyBytes, macKeyBytes; private Cipher aesCipher, rsaDecryptCipher, rsaEncryptCipher; private Mac macSignature; private PrivateKey rsaPrivateKey; private SecretKey aesKey, macKey; private PublicKey rsaPublicKey; private AlgorithmParameterSpec cipherParamSpec; private BlumBlumShub randomize; /** * Constructor */ public CryptManager() { System.out.println("Inizializzazione randomizzatore"); randomize = new BlumBlumShub(128); System.out.println("Randomizzatore inizializzato"); } /** * Initialize RSA Keys and Ciphers. All RSA keys MUST be Base64Decode first! * * @param privateKeyFragment1 First half of the Private Key * @param privateKeyFragment2 Second half of the Private Key * @param publicKey Public Key * @throws java.security.NoSuchAlgorithmException * @throws java.security.spec.InvalidKeySpecException * @throws javax.crypto.NoSuchPaddingException * @throws java.security.InvalidKeyException * @throws com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException */ public void initRsaOperations(byte[] privateKeyFragment1, byte[] privateKeyFragment2, byte[] publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, Base64DecodingException, UnsupportedEncodingException, DestroyFailedException { initPrivateKey(privateKeyFragment1, privateKeyFragment2); this.rsaPublicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey)); this.rsaDecryptCipher = Cipher.getInstance("RSA"); this.rsaDecryptCipher.init(Cipher.DECRYPT_MODE, this.rsaPrivateKey); this.rsaEncryptCipher = Cipher.getInstance("RSA"); this.rsaEncryptCipher.init(Cipher.ENCRYPT_MODE, this.rsaPublicKey); } /** * Initialize AES-128-CBC Key and Cipher with PKCS5 Padding. * * @param aesKeyBytes * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public void initAesOperations(byte[] aesKeyBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, Base64DecodingException, DecoderException { this.aesKey = new SecretKeySpec(Hex.decodeHex(new String(aesKeyBytes).toCharArray()), "AES"); this.aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); } /** * Initialize AES-128-CBC Key and Cipher with PKCS5 Padding. * * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public String initAesOperations() throws NoSuchAlgorithmException, NoSuchPaddingException, Base64DecodingException, DecoderException { byte[] aesKeyBytes = new byte[16]; this.randomize.nextBytes(aesKeyBytes); this.aesKey = new SecretKeySpec(aesKeyBytes, "AES"); this.aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); return Hex.encodeHexString(aesKeyBytes); } /** * Initialize HMAC-SHA1 key and cipher. * * @param macKeyBytes * @throws NoSuchAlgorithmException */ public void initHmacOperations(byte[] macKeyBytes) throws NoSuchAlgorithmException, Base64DecodingException, DecoderException { this.macKey = new SecretKeySpec(Hex.decodeHex(new String(macKeyBytes).toCharArray()), "HmacSHA1"); this.macSignature = Mac.getInstance("HmacSHA1"); } /** * Initialize HMAC-SHA1 key and cipher. * * @param macKeyBytes * @throws NoSuchAlgorithmException */ public void initHmacOperations() throws NoSuchAlgorithmException, Base64DecodingException, DecoderException { byte[] macKeyBytes = new byte[40]; this.randomize.nextBytes(macKeyBytes); this.macKey = new SecretKeySpec(macKeyBytes, "HmacSHA1"); this.macSignature = Mac.getInstance("HmacSHA1"); } /** * Initialize all the keys and the ciphers. All RSA keys MUST be Base64Decode first! * * @param privateKeyFragment1 * @param privateKeyFragment2 * @param publicKey * @param aesKey * @param macKey * @throws java.security.NoSuchAlgorithmException * @throws java.security.spec.InvalidKeySpecException * @throws javax.crypto.NoSuchPaddingException * @throws java.security.InvalidKeyException */ public void initAll(byte[] privateKeyFragment1, byte[] privateKeyFragment2, byte[] publicKey, byte[] aesKey, byte[] macKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, Base64DecodingException, UnsupportedEncodingException, DestroyFailedException, DecoderException { initRsaOperations(privateKeyFragment1, privateKeyFragment2, publicKey); initAesOperations(aesKey); initHmacOperations(macKey); } /** * Initialize all the keys and the ciphers. All RSA keys MUST be Base64Decode first! * * @param privateKeyFragment1 * @param privateKeyFragment2 * @param publicKey * @throws java.security.NoSuchAlgorithmException * @throws java.security.spec.InvalidKeySpecException * @throws javax.crypto.NoSuchPaddingException * @throws java.security.InvalidKeyException */ public String initAll(byte[] privateKeyFragment1, byte[] privateKeyFragment2, byte[] publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, Base64DecodingException, UnsupportedEncodingException, DestroyFailedException, DecoderException { initRsaOperations(privateKeyFragment1, privateKeyFragment2, publicKey); String preSharedKey = initAesOperations(); initHmacOperations(); return preSharedKey; } /** * Returns the ciphered HMAC-SHA1 Key. * * @return Ciphered HMAC-SHA1 key: to be Base64-encoded * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException */ public byte[] getAesCipheredMacKey() throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, Base64DecodingException, NoSuchAlgorithmException { byte[] Iv = new byte[16]; randomize.nextBytes(Iv); this.cipherParamSpec = new IvParameterSpec(Iv); this.aesCipher.init(Cipher.ENCRYPT_MODE, this.aesKey, cipherParamSpec); byte[] encryptedMacKey = this.aesCipher.doFinal(this.macKey.getEncoded()); return concatByteArrays(Iv, encryptedMacKey); } /** * Encrypt the plain text value using AES-128-CBC/PKCS5Padding. * * @param plainValue Value to encrypt. * @return Ciphered secret. * @throws InvalidKeyException * @throws InvalidAlgorithmParameterException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException */ public byte[] aesEncryptSecret(byte[] plainValue) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, Base64DecodingException, UnsupportedEncodingException, NoSuchAlgorithmException, DecoderException { byte[] Iv = new byte[16]; // MUST be random randomize.nextBytes(Iv); byte[] secretBytes = Hex.decodeHex(new String(plainValue).trim().toCharArray()); this.cipherParamSpec = new IvParameterSpec(Iv); this.aesCipher.init(Cipher.ENCRYPT_MODE, this.aesKey, this.cipherParamSpec); byte[] encryptedSecret = this.aesCipher.doFinal(secretBytes); return concatByteArrays(Iv, encryptedSecret); } /** * Compute HMAC-SHA1 signature for the given ciphered secret. * * @param cipheredSecret Ciphered secret to sign. * @return Signature. */ public byte[] signCipheredSecret(byte[] cipheredSecret) throws Base64DecodingException, NoSuchAlgorithmException, InvalidKeyException { this.macSignature = Mac.getInstance("HmacSHA1"); this.macSignature.init(new SecretKeySpec(this.macKey.getEncoded(), "HmacSHA1")); return this.macSignature.doFinal(cipheredSecret); } /** * Not implemented: not needed. * * @param cipheredSecret * @return */ public byte[] aesDecryptCipheredSecret(byte[] cipheredSecret) { return null; } public byte[] convertRsaToAes(String rsaCipheredSecret) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, Base64DecodingException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, DecoderException { return this.aesEncryptSecret(this.rsaDecryptSecret(rsaCipheredSecret)); } /** * Recover the full private key as bytes array and initialize the PrivateKey. * Fragments MUST be Base64Decode first! * * @param privateKeyFragment1 First half of the Private Key. * @param privateKeyFragment2 Second half of the Private Key. * * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ private void initPrivateKey(byte[] privateKeyFragment1, byte[] privateKeyFragment2) throws NoSuchAlgorithmException, InvalidKeySpecException, Base64DecodingException { this.rsaPrivateKey = KeyFactory.getInstance("RSA").generatePrivate( new PKCS8EncodedKeySpec(concatByteArrays(privateKeyFragment1, privateKeyFragment2))); } /** * Concat byte arrays. * * @param piece1 * @param piece2 * @return */ private byte[] concatByteArrays(byte[] piece1, byte[] piece2) throws Base64DecodingException { byte[] result = new byte[piece1.length + piece2.length]; System.arraycopy(piece1, 0, result, 0, piece1.length); System.arraycopy(piece2, 0, result, piece1.length, piece2.length); return result; } private byte[] rsaDecryptSecret(String cipheredSecret) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, Base64DecodingException { this.rsaDecryptCipher = Cipher.getInstance("RSA"); this.rsaDecryptCipher.init(Cipher.DECRYPT_MODE, this.rsaPrivateKey); return this.rsaDecryptCipher.doFinal(Base64.decode(cipheredSecret)); } public void initRsaOperations(byte[] fragment1, byte[] fragment2) throws NoSuchAlgorithmException, InvalidKeySpecException, Base64DecodingException, NoSuchPaddingException, InvalidKeyException { initPrivateKey(fragment1, fragment2); this.rsaDecryptCipher = Cipher.getInstance("RSA"); this.rsaDecryptCipher.init(Cipher.DECRYPT_MODE, this.rsaPrivateKey); } }