您现在的位置是:首页 > 文章详情

安卓应用安全指南 5.6.1 密码学 示例代码

日期:2018-04-04点击:352

5.6.1 密码学 示例代码

原书:Android Application Secure Design/Secure Coding Guidebook

译者:飞龙

协议:CC BY-NC-SA 4.0

针对特定用途和条件开发了各种加密方法,包括加密和解密数据(来确保机密性)和检测数据伪造(来确保完整性)等用例。 以下是示例代码,根据每种技术的目的分为三大类加密技术。 在每种情况下,应该能够根据密码技术的特点,选择适当的加密方法和密钥类型。 对于需要更详细考虑的情况,请参见章节“5.6.3.1 选择加密方法”。

在使用加密技术设计实现之前,请务必阅读“5.6.3.3 防止随机数字生成器中的漏洞的措施”。

保护数据免受第三方窃听

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

5.6.1.1 使用基于密码的密钥的加密和解密

你可以使用基于密码的密钥加密,来保护用户的机密数据资产。

要点:

  1. 显式指定加密模式和填充。
  2. 使用强加密技术(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  3. 从密码生成密钥时,使用盐。
  4. 从密码生成密钥时,指定适当的哈希迭代计数。
  5. 使用足以保证加密强度的密钥长度。

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=PKCS7Padding private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding"; // A string used to fetch an instance of the class that generates the key private static final String KEY_GENERATOR_MODE = "PBEWITHSHA256AND128BITAES-CBC-BC"; // *** POINT 3 *** When generating a key from a password, use Salt. // Salt length in bytes public 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 PBE private 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 bits private 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 password Arrays.fill(password, '?'); // Generate the key secretKey = secretKeyFactory.generateSecret(keySpec); } catch (NoSuchAlgorithmException e) { } catch (InvalidKeySpecException e) { } finally { keySpec.clearPassword(); } return secretKey; } }

5.6.1.2 使用公钥的加密和解密

在某些情况下,数据加密仅在应用端使用存储的公钥来执行,而解密在单独安全位置(如服务器)在私钥下执行。 在这种情况下,可以使用公钥(非对称密钥)加密。

要点:

  1. 显式指定加密模式和填充
  2. 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  3. 使用足以保证加密强度的密钥长度。

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 algorithm private 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 key private 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 key if (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 使用预共享密钥的加密和解密

预共享密钥可用于处理大型数据集,或保护应用或用户资产的机密性。

要点:

  1. 显式指定加密模式和填充
  2. 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  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 cr iteria), 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=PKCS7Padding private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding"; // Encryption algorithm private static final String KEY_ALGORITHM = "AES"; // Length of IV in bytes public 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 key private 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 encryption 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; } }

5.6.1.4 使用基于密码的密钥来检测数据伪造

你可以使用基于密码的(共享密钥)加密来验证用户数据的完整性。

要点:

  1. 显式指定加密模式和填充。
  2. 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  3. 从密码生成密钥时,使用盐。
  4. 从密码生成密钥时,指定适当的哈希迭代计数。
  5. 使用足以保证 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 mode private static final String TRANSFORMATION = "PBEWITHHMACSHA1"; // A string used to fetch an instance of the class that generates the key private static final String KEY_GENERATOR_MODE = "PBEWITHHMACSHA1"; // *** POINT 3 *** When generating a key from a password, use Salt. // Salt length in bytes public 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 PBE private static final int KEY_GEN_ITERATION_COUNT = 1024; // *** POINT 5 *** Use a key of length sufficient to guarantee the MAC strength. // Key length in bits private 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 password Arrays.fill(password, '?'); // Generate the key secretKey = secretKeyFactory.generateSecret(keySpec); } catch (NoSuchAlgorithmException e) { } catch (InvalidKeySpecException e) { } finally { keySpec.clearPassword(); } return secretKey; } }

5.6.1.5 使用公钥来检测数据伪造

所处理的数据的签名,由存储在不同的安全位置(如服务器)中的私钥确定时,你可以使用公钥(不对称密钥)加密来处理涉及应用端公钥存储的应用,出于验证数据签名的目的。

要点:

  1. 显式指定加密模式和填充。
  2. 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  3. 使用足以保证签名强度的密钥长度。

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 algorithm private static final String KEY_ALGORITHM = "RSA"; // *** POINT 3 *** Use a key of length sufficient to guarantee the signature strength. // Check the length of the key private 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 key if (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 使用预共享密钥来检测数据伪造

你可以使用预共享密钥来验证应用资产或用户资产的完整性。

要点:

  1. 显式指定加密模式和填充。
  2. 使用强加密方法(特别是符合相关标准的技术),包括算法,分组加密模式和填充模式。
  3. 使用足以保证 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 mode private static final String TRANSFORMATION = "HmacSHA256"; // Encryption algorithm private static final String KEY_ALGORITHM = "HmacSHA256"; // *** POINT 3 *** Use a key of length sufficient to guarantee the MAC strength. // Check the length of the key private 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; } }
原文链接:https://yq.aliyun.com/articles/595238
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章