5.6.1 示例代码
针对特定用途和条件开发了各种加密方法,包括加密和解密数据(来确保机密性)和检测数据伪造(来确保完整性)等用例。 以下是示例代码,根据每种技术的目的分为三大类加密技术。 在每种情况下,应该能够根据密码技术的特点,选择适当的加密方法和密钥类型。 对于需要更详细考虑的情况,请参见章节“5.6.3.1 选择加密方法”。
在使用加密技术设计实现之前,请务必阅读“5.6.3.3 防止随机数字生成器中的漏洞的措施”。
保护数据免受第三方窃听

检测第三方所做的数据伪造

5.6.1.1 使用基于密码的密钥的加密和解密
你可以使用基于密码的密钥加密,来保护用户的机密数据资产。
要点:
- 显式指定加密模式和填充。
- 使用强加密技术(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 从密码生成密钥时,使用盐。
- 从密码生成密钥时,指定适当的哈希迭代计数。
- 使用足以保证加密强度的密钥长度。
AesCryptoPBEKey.java
package org.jssec.android.cryptsymmetricpasswordbasedkey;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.spec.InvalidKeySpecException;import java.util.Arrays;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.PBEKeySpec;public final class AesCryptoPBEKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Parameters passed to the getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule// In this sample, we choose the following parameter values: encryption algorithm=AES, block encryption mode=CBC, padding rule=PKCS7Paddingprivate static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";// A string used to fetch an instance of the class that generates the keyprivate static final String KEY_GENERATOR_MODE = "PBEWITHSHA256AND128BITAES-CBC-BC";// *** POINT 3 *** When generating a key from a password, use Salt.// Salt length in bytespublic static final int SALT_LENGTH_BYTES = 20;// *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.// Set the number of mixing repetitions used when generating keys via PBEprivate static final int KEY_GEN_ITERATION_COUNT = 1024;// *** POINT 5 *** Use a key of length sufficient to guarantee the strength of encryption.// Key length in bitsprivate static final int KEY_LENGTH_BITS = 128;private byte[] mIV = null;private byte[] mSalt = null;public byte[] getIV() {return mIV;}public byte[] getSalt() {return mSalt;}AesCryptoPBEKey(final byte[] iv, final byte[] salt) {mIV = iv;mSalt = salt;}AesCryptoPBEKey() {mIV = null;initSalt();}private void initSalt() {mSalt = new byte[SALT_LENGTH_BYTES];SecureRandom sr = new SecureRandom();sr.nextBytes(mSalt);}public final byte[] encrypt(final byte[] plain, final char[] password) {byte[] encrypted = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, modes, and padding.Cipher cipher = Cipher.getInstance(TRANSFORMATION);// *** POINT 3 *** When generating keys from passwords, use Salt.SecretKey secretKey = generateKey(password, mSalt);cipher.init(Cipher.ENCRYPT_MODE, secretKey);mIV = cipher.getIV();encrypted = cipher.doFinal(plain);} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return encrypted;}public final byte[] decrypt(final byte[] encrypted, final char[] password) {byte[] plain = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Cipher cipher = Cipher.getInstance(TRANSFORMATION);// *** POINT 3 *** When generating a key from a password, use Salt.SecretKey secretKey = generateKey(password, mSalt);IvParameterSpec ivParameterSpec = new IvParameterSpec(mIV);cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);plain = cipher.doFinal(encrypted);} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (InvalidAlgorithmParameterException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return plain;}private static final SecretKey generateKey(final char[] password, final byte[] salt) {SecretKey secretKey = null;PBEKeySpec keySpec = null;try {// *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Fetch an instance of the class that generates the key// In this example, we use a KeyFactory that uses SHA256 to generate AES-CBC 128-bit keys.SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);// *** POINT 3 *** When generating a key from a password, use Salt.// *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.// *** POINT 5 *** Use a key of length sufficient to guarantee the strength of encryption.keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);// Clear passwordArrays.fill(password, '?');// Generate the keysecretKey = secretKeyFactory.generateSecret(keySpec);} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {keySpec.clearPassword();}return secretKey;}}
5.6.1.2 使用公钥的加密和解密
在某些情况下,数据加密仅在应用端使用存储的公钥来执行,而解密在单独安全位置(如服务器)在私钥下执行。 在这种情况下,可以使用公钥(非对称密钥)加密。
要点:
- 显式指定加密模式和填充
- 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 使用足以保证加密强度的密钥长度。
RsaCryptoAsymmetricKey.java
package org.jssec.android.cryptasymmetrickey;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.interfaces.RSAPublicKey;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.NoSuchPaddingException;public final class RsaCryptoAsymmetricKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..// Parameters passed to getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule// In this sample, we choose the following parameter values: encryption algorithm=RSA, block encryption mode=NONE, padding rule=OAEPPADDING.private static final String TRANSFORMATION = "RSA/NONE/OAEPPADDING";// encryption algorithmprivate static final String KEY_ALGORITHM = "RSA";// *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption.// Check the length of the keyprivate static final int MIN_KEY_LENGTH = 2000;RsaCryptoAsymmetricKey() {}public final byte[] encrypt(final byte[] plain, final byte[] keyData) {byte[] encrypted = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..Cipher cipher = Cipher.getInstance(TRANSFORMATION);PublicKey publicKey = generatePubKey(keyData);if (publicKey != null) {cipher.init(Cipher.ENCRYPT_MODE, publicKey);encrypted = cipher.doFinal(plain);}} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return encrypted;}public final byte[] decrypt(final byte[] encrypted, final byte[] keyData) {// In general, decryption procedures should be implemented on the server side;// however, in this sample code we have implemented decryption processing within the application to ensure confirmation of proper execution.// When using this sample code in real-world applications, be careful not to retain any private keys within the application.byte[] plain = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..Cipher cipher = Cipher.getInstance(TRANSFORMATION);PrivateKey privateKey = generatePriKey(keyData);cipher.init(Cipher.DECRYPT_MODE, privateKey);plain = cipher.doFinal(encrypted);} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return plain;}private static final PublicKey generatePubKey(final byte[] keyData) {PublicKey publicKey = null;KeyFactory keyFactory = null;try {keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyData));} catch (IllegalArgumentException e) {} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {}// *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption.// Check the length of the keyif (publicKey instanceof RSAPublicKey) {int len = ((RSAPublicKey) publicKey).getModulus().bitLength();if (len < MIN_KEY_LENGTH) {publicKey = null;}}return publicKey;}private static final PrivateKey generatePriKey(final byte[] keyData) {PrivateKey privateKey = null;KeyFactory keyFactory = null;try {keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyData));} catch (IllegalArgumentException e) {} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {}return privateKey;}}
5.6.1.3 使用预共享密钥的加密和解密
预共享密钥可用于处理大型数据集,或保护应用或用户资产的机密性。
要点:
- 显式指定加密模式和填充
- 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 使用足以保证加密强度的密钥长度。
AesCryptoPreSharedKey.java
package org.jssec.android.cryptsymmetricpresharedkey;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.SecretKey;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;public final class AesCryptoPreSharedKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Parameters passed to getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule// In this sample, we choose the following parameter values: encryption algorithm=AES, block encryption mode=CBC, padding rule=PKCS7Paddingprivate static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";// Encryption algorithmprivate static final String KEY_ALGORITHM = "AES";// Length of IV in bytespublic static final int IV_LENGTH_BYTES = 16;// *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption// Check the length of the keyprivate static final int MIN_KEY_LENGTH_BYTES = 16;private byte[] mIV = null;public byte[] getIV() {return mIV;}AesCryptoPreSharedKey(final byte[] iv) {mIV = iv;}AesCryptoPreSharedKey() {}public final byte[] encrypt(final byte[] keyData, final byte[] plain) {byte[] encrypted = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Cipher cipher = Cipher.getInstance(TRANSFORMATION);SecretKey secretKey = generateKey(keyData);if (secretKey != null) {cipher.init(Cipher.ENCRYPT_MODE, secretKey);mIV = cipher.getIV();encrypted = cipher.doFinal(plain);}} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return encrypted;}public final byte[] decrypt(final byte[] keyData, final byte[] encrypted) {byte[] plain = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Cipher cipher = Cipher.getInstance(TRANSFORMATION);SecretKey secretKey = generateKey(keyData);if (secretKey != null) {IvParameterSpec ivParameterSpec = new IvParameterSpec(mIV);cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);plain = cipher.doFinal(encrypted);}} catch (NoSuchAlgorithmException e) {} catch (NoSuchPaddingException e) {} catch (InvalidKeyException e) {} catch (InvalidAlgorithmParameterException e) {} catch (IllegalBlockSizeException e) {} catch (BadPaddingException e) {} finally {}return plain;}private static final SecretKey generateKey(final byte[] keyData) {SecretKey secretKey = null;try {// *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryptionif (keyData.length >= MIN_KEY_LENGTH_BYTES) {// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.secretKey = new SecretKeySpec(keyData, KEY_ALGORITHM);}} catch (IllegalArgumentException e) {} finally {}return secretKey;}}
5.6.1.4 使用基于密码的密钥来检测数据伪造
你可以使用基于密码的(共享密钥)加密来验证用户数据的完整性。
要点:
- 显式指定加密模式和填充。
- 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 从密码生成密钥时,使用盐。
- 从密码生成密钥时,指定适当的哈希迭代计数。
- 使用足以保证 MAC 强度的密钥长度。
HmacPBEKey.java
package org.jssec.android.signsymmetricpasswordbasedkey;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.spec.InvalidKeySpecException;import java.util.Arrays;import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.PBEKeySpec;public final class HmacPBEKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Parameters passed to the getInstance method of the Mac class: Authentication modeprivate static final String TRANSFORMATION = "PBEWITHHMACSHA1";// A string used to fetch an instance of the class that generates the keyprivate static final String KEY_GENERATOR_MODE = "PBEWITHHMACSHA1";// *** POINT 3 *** When generating a key from a password, use Salt.// Salt length in bytespublic static final int SALT_LENGTH_BYTES = 20;// *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.// Set the number of mixing repetitions used when generating keys via PBEprivate static final int KEY_GEN_ITERATION_COUNT = 1024;// *** POINT 5 *** Use a key of length sufficient to guarantee the MAC strength.// Key length in bitsprivate static final int KEY_LENGTH_BITS = 160;private byte[] mSalt = null;public byte[] getSalt() {return mSalt;}HmacPBEKey() {initSalt();}HmacPBEKey(final byte[] salt) {mSalt = salt;}private void initSalt() {mSalt = new byte[SALT_LENGTH_BYTES];SecureRandom sr = new SecureRandom();sr.nextBytes(mSalt);}public final byte[] sign(final byte[] plain, final char[] password) {return calculate(plain, password);}private final byte[] calculate(final byte[] plain, final char[] password) {byte[] hmac = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Mac mac = Mac.getInstance(TRANSFORMATION);// *** POINT 3 *** When generating a key from a password, use Salt.SecretKey secretKey = generateKey(password, mSalt);mac.init(secretKey);hmac = mac.doFinal(plain);} catch (NoSuchAlgorithmException e) {} catch (InvalidKeyException e) {} finally {}return hmac;}public final boolean verify(final byte[] hmac, final byte[] plain, final char[] password) {byte[] hmacForPlain = calculate(plain, password);if (Arrays.equals(hmac, hmacForPlain)) {return true;}return false;}private static final SecretKey generateKey(final char[] password, final byte[] salt) {SecretKey secretKey = null;PBEKeySpec keySpec = null;try {// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Fetch an instance of the class that generates the key// In this example, we use a KeyFactory that uses SHA1 to generate AES-CBC 128-bit keys.SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);// *** POINT 3 *** When generating a key from a password, use Salt.// *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.// *** POINT 5 *** Use a key of length sufficient to guarantee the MAC strength.keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);// Clear passwordArrays.fill(password, '?');// Generate the keysecretKey = secretKeyFactory.generateSecret(keySpec);} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {keySpec.clearPassword();}return secretKey;}}
5.6.1.5 使用公钥来检测数据伪造
所处理的数据的签名,由存储在不同的安全位置(如服务器)中的私钥确定时,你可以使用公钥(不对称密钥)加密来处理涉及应用端公钥存储的应用,出于验证数据签名的目的。
要点:
- 显式指定加密模式和填充。
- 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 使用足以保证签名强度的密钥长度。
RsaSignAsymmetricKey.java
package org.jssec.android.signasymmetrickey;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.Signature;import java.security.SignatureException;import java.security.interfaces.RSAPublicKey;import java.security.spec.InvalidKeySpecException;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;public final class RsaSignAsymmetricKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Parameters passed to the getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule// In this sample, we choose the following parameter values: encryption algorithm=RSA, block encryption mode=NONE, padding rule=OAEPPADDING.private static final String TRANSFORMATION = "SHA256withRSA";// encryption algorithmprivate static final String KEY_ALGORITHM = "RSA";// *** POINT 3 *** Use a key of length sufficient to guarantee the signature strength.// Check the length of the keyprivate static final int MIN_KEY_LENGTH = 2000;RsaSignAsymmetricKey() {}public final byte[] sign(final byte[] plain, final byte[] keyData) {// In general, signature procedures should be implemented on the server side;// however, in this sample code we have implemented signature processing within the application to ensure confirmation of proper execution.// When using this sample code in real-world applications, be careful not to retain any private keys within the application.byte[] sign = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Signature signature = Signature.getInstance(TRANSFORMATION);PrivateKey privateKey = generatePriKey(keyData);signature.initSign(privateKey);signature.update(plain);sign = signature.sign();} catch (NoSuchAlgorithmException e) {} catch (InvalidKeyException e) {} catch (SignatureException e) {} finally {}return sign;}public final boolean verify(final byte[] sign, final byte[] plain, final byte[] keyData) {boolean ret = false;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Signature signature = Signature.getInstance(TRANSFORMATION);PublicKey publicKey = generatePubKey(keyData);signature.initVerify(publicKey);signature.update(plain);ret = signature.verify(sign);} catch (NoSuchAlgorithmException e) {} catch (InvalidKeyException e) {} catch (SignatureException e) {} finally {}return ret;}private static final PublicKey generatePubKey(final byte[] keyData) {PublicKey publicKey = null;KeyFactory keyFactory = null;try {keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyData));} catch (IllegalArgumentException e) {} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {}// *** POINT 3 *** Use a key of length sufficient to guarantee the signature strength.// Check the length of the keyif (publicKey instanceof RSAPublicKey) {int len = ((RSAPublicKey) publicKey).getModulus().bitLength();if (len < MIN_KEY_LENGTH) {publicKey = null;}}return publicKey;}private static final PrivateKey generatePriKey(final byte[] keyData) {PrivateKey privateKey = null;KeyFactory keyFactory = null;try {keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyData));} catch (IllegalArgumentException e) {} catch (NoSuchAlgorithmException e) {} catch (InvalidKeySpecException e) {} finally {}return privateKey;}}
5.6.1.6 使用预共享密钥来检测数据伪造
你可以使用预共享密钥来验证应用资产或用户资产的完整性。
要点:
- 显式指定加密模式和填充。
- 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
- 使用足以保证 MAC 强度的密钥长度。
HmacPreSharedKey.java
package org.jssec.android.signsymmetricpresharedkey;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.Arrays;import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public final class HmacPreSharedKey {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.// Parameters passed to the getInstance method of the Mac class: Authentication modeprivate static final String TRANSFORMATION = "HmacSHA256";// Encryption algorithmprivate static final String KEY_ALGORITHM = "HmacSHA256";// *** POINT 3 *** Use a key of length sufficient to guarantee the MAC strength.// Check the length of the keyprivate static final int MIN_KEY_LENGTH_BYTES = 16;HmacPreSharedKey() {}public final byte[] sign(final byte[] plain, final byte[] keyData) {return calculate(plain, keyData);}public final byte[] calculate(final byte[] plain, final byte[] keyData) {byte[] hmac = null;try {// *** POINT 1 *** Explicitly specify the encryption mode and the padding.// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.Mac mac = Mac.getInstance(TRANSFORMATION);SecretKey secretKey = generateKey(keyData);if (secretKey != null) {mac.init(secretKey);hmac = mac.doFinal(plain);}} catch (NoSuchAlgorithmException e) {} catch (InvalidKeyException e) {} finally {}return hmac;}public final boolean verify(final byte[] hmac, final byte[] plain, final byte[] keyData) {byte[] hmacForPlain = calculate(plain, keyData);if (hmacForPlain != null && Arrays.equals(hmac, hmacForPlain)) {return true;}return false;}private static final SecretKey generateKey(final byte[] keyData) {SecretKey secretKey = null;try {// *** POINT 3 *** Use a key of length sufficient to guarantee the MAC strength.if (keyData.length >= MIN_KEY_LENGTH_BYTES) {// *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.secretKey = new SecretKeySpec(keyData, KEY_ALGORITHM);}} catch (IllegalArgumentException e) {} finally {}return secretKey;}}
