5.6.1 示例代码

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

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

保护数据免受第三方窃听

5.6.1.md - 图1

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

5.6.1.md - 图2

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

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

要点:

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

AesCryptoPBEKey.java

  1. package org.jssec.android.cryptsymmetricpasswordbasedkey;
  2. import java.security.InvalidAlgorithmParameterException;
  3. import java.security.InvalidKeyException;
  4. import java.security.NoSuchAlgorithmException;
  5. import java.security.SecureRandom;
  6. import java.security.spec.InvalidKeySpecException;
  7. import java.util.Arrays;
  8. import javax.crypto.BadPaddingException;
  9. import javax.crypto.Cipher;
  10. import javax.crypto.IllegalBlockSizeException;
  11. import javax.crypto.NoSuchPaddingException;
  12. import javax.crypto.SecretKey;
  13. import javax.crypto.SecretKeyFactory;
  14. import javax.crypto.spec.IvParameterSpec;
  15. import javax.crypto.spec.PBEKeySpec;
  16. public final class AesCryptoPBEKey {
  17. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  18. // *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  19. // Parameters passed to the getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule
  20. // In this sample, we choose the following parameter values: encryption algorithm=AES, block encryption mode=CBC, padding rule=PKCS7Padding
  21. private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";
  22. // A string used to fetch an instance of the class that generates the key
  23. private static final String KEY_GENERATOR_MODE = "PBEWITHSHA256AND128BITAES-CBC-BC";
  24. // *** POINT 3 *** When generating a key from a password, use Salt.
  25. // Salt length in bytes
  26. public static final int SALT_LENGTH_BYTES = 20;
  27. // *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.
  28. // Set the number of mixing repetitions used when generating keys via PBE
  29. private static final int KEY_GEN_ITERATION_COUNT = 1024;
  30. // *** POINT 5 *** Use a key of length sufficient to guarantee the strength of encryption.
  31. // Key length in bits
  32. private static final int KEY_LENGTH_BITS = 128;
  33. private byte[] mIV = null;
  34. private byte[] mSalt = null;
  35. public byte[] getIV() {
  36. return mIV;
  37. }
  38. public byte[] getSalt() {
  39. return mSalt;
  40. }
  41. AesCryptoPBEKey(final byte[] iv, final byte[] salt) {
  42. mIV = iv;
  43. mSalt = salt;
  44. }
  45. AesCryptoPBEKey() {
  46. mIV = null;
  47. initSalt();
  48. }
  49. private void initSalt() {
  50. mSalt = new byte[SALT_LENGTH_BYTES];
  51. SecureRandom sr = new SecureRandom();
  52. sr.nextBytes(mSalt);
  53. }
  54. public final byte[] encrypt(final byte[] plain, final char[] password) {
  55. byte[] encrypted = null;
  56. try {
  57. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  58. // *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, modes, and padding.
  59. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  60. // *** POINT 3 *** When generating keys from passwords, use Salt.
  61. SecretKey secretKey = generateKey(password, mSalt);
  62. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  63. mIV = cipher.getIV();
  64. encrypted = cipher.doFinal(plain);
  65. } catch (NoSuchAlgorithmException e) {
  66. } catch (NoSuchPaddingException e) {
  67. } catch (InvalidKeyException e) {
  68. } catch (IllegalBlockSizeException e) {
  69. } catch (BadPaddingException e) {
  70. } finally {
  71. }
  72. return encrypted;
  73. }
  74. public final byte[] decrypt(final byte[] encrypted, final char[] password) {
  75. byte[] plain = null;
  76. try {
  77. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  78. // *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  79. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  80. // *** POINT 3 *** When generating a key from a password, use Salt.
  81. SecretKey secretKey = generateKey(password, mSalt);
  82. IvParameterSpec ivParameterSpec = new IvParameterSpec(mIV);
  83. cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
  84. plain = cipher.doFinal(encrypted);
  85. } catch (NoSuchAlgorithmException e) {
  86. } catch (NoSuchPaddingException e) {
  87. } catch (InvalidKeyException e) {
  88. } catch (InvalidAlgorithmParameterException e) {
  89. } catch (IllegalBlockSizeException e) {
  90. } catch (BadPaddingException e) {
  91. } finally {
  92. }
  93. return plain;
  94. }
  95. private static final SecretKey generateKey(final char[] password, final byte[] salt) {
  96. SecretKey secretKey = null;
  97. PBEKeySpec keySpec = null;
  98. try {
  99. // *** POINT 2 *** Use strong encryption technologies (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  100. // Fetch an instance of the class that generates the key
  101. // In this example, we use a KeyFactory that uses SHA256 to generate AES-CBC 128-bit keys.
  102. SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);
  103. // *** POINT 3 *** When generating a key from a password, use Salt.
  104. // *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.
  105. // *** POINT 5 *** Use a key of length sufficient to guarantee the strength of encryption.
  106. keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);
  107. // Clear password
  108. Arrays.fill(password, '?');
  109. // Generate the key
  110. secretKey = secretKeyFactory.generateSecret(keySpec);
  111. } catch (NoSuchAlgorithmException e) {
  112. } catch (InvalidKeySpecException e) {
  113. } finally {
  114. keySpec.clearPassword();
  115. }
  116. return secretKey;
  117. }
  118. }

5.6.1.2 使用公钥的加密和解密

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

要点:

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

RsaCryptoAsymmetricKey.java

  1. package org.jssec.android.cryptasymmetrickey;
  2. import java.security.InvalidKeyException;
  3. import java.security.KeyFactory;
  4. import java.security.NoSuchAlgorithmException;
  5. import java.security.PrivateKey;
  6. import java.security.PublicKey;
  7. import java.security.interfaces.RSAPublicKey;
  8. import java.security.spec.InvalidKeySpecException;
  9. import java.security.spec.PKCS8EncodedKeySpec;
  10. import java.security.spec.X509EncodedKeySpec;
  11. import javax.crypto.BadPaddingException;
  12. import javax.crypto.Cipher;
  13. import javax.crypto.IllegalBlockSizeException;
  14. import javax.crypto.NoSuchPaddingException;
  15. public final class RsaCryptoAsymmetricKey {
  16. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  17. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..
  18. // Parameters passed to getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule
  19. // In this sample, we choose the following parameter values: encryption algorithm=RSA, block encryption mode=NONE, padding rule=OAEPPADDING.
  20. private static final String TRANSFORMATION = "RSA/NONE/OAEPPADDING";
  21. // encryption algorithm
  22. private static final String KEY_ALGORITHM = "RSA";
  23. // *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption.
  24. // Check the length of the key
  25. private static final int MIN_KEY_LENGTH = 2000;
  26. RsaCryptoAsymmetricKey() {
  27. }
  28. public final byte[] encrypt(final byte[] plain, final byte[] keyData) {
  29. byte[] encrypted = null;
  30. try {
  31. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  32. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..
  33. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  34. PublicKey publicKey = generatePubKey(keyData);
  35. if (publicKey != null) {
  36. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  37. encrypted = cipher.doFinal(plain);
  38. }
  39. } catch (NoSuchAlgorithmException e) {
  40. } catch (NoSuchPaddingException e) {
  41. } catch (InvalidKeyException e) {
  42. } catch (IllegalBlockSizeException e) {
  43. } catch (BadPaddingException e) {
  44. } finally {
  45. }
  46. return encrypted;
  47. }
  48. public final byte[] decrypt(final byte[] encrypted, final byte[] keyData) {
  49. // In general, decryption procedures should be implemented on the server side;
  50. // however, in this sample code we have implemented decryption processing within the application to ensure confirmation of proper execution.
  51. // When using this sample code in real-world applications, be careful not to retain any private keys within the application.
  52. byte[] plain = null;
  53. try {
  54. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  55. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes..
  56. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  57. PrivateKey privateKey = generatePriKey(keyData);
  58. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  59. plain = cipher.doFinal(encrypted);
  60. } catch (NoSuchAlgorithmException e) {
  61. } catch (NoSuchPaddingException e) {
  62. } catch (InvalidKeyException e) {
  63. } catch (IllegalBlockSizeException e) {
  64. } catch (BadPaddingException e) {
  65. } finally {
  66. }
  67. return plain;
  68. }
  69. private static final PublicKey generatePubKey(final byte[] keyData) {
  70. PublicKey publicKey = null;
  71. KeyFactory keyFactory = null;
  72. try {
  73. keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  74. publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyData));
  75. } catch (IllegalArgumentException e) {
  76. } catch (NoSuchAlgorithmException e) {
  77. } catch (InvalidKeySpecException e) {
  78. } finally {
  79. }
  80. // *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption.
  81. // Check the length of the key
  82. if (publicKey instanceof RSAPublicKey) {
  83. int len = ((RSAPublicKey) publicKey).getModulus().bitLength();
  84. if (len < MIN_KEY_LENGTH) {
  85. publicKey = null;
  86. }
  87. }
  88. return publicKey;
  89. }
  90. private static final PrivateKey generatePriKey(final byte[] keyData) {
  91. PrivateKey privateKey = null;
  92. KeyFactory keyFactory = null;
  93. try {
  94. keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  95. privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyData));
  96. } catch (IllegalArgumentException e) {
  97. } catch (NoSuchAlgorithmException e) {
  98. } catch (InvalidKeySpecException e) {
  99. } finally {
  100. }
  101. return privateKey;
  102. }
  103. }

5.6.1.3 使用预共享密钥的加密和解密

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

要点:

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

AesCryptoPreSharedKey.java

  1. package org.jssec.android.cryptsymmetricpresharedkey;
  2. import java.security.InvalidAlgorithmParameterException;
  3. import java.security.InvalidKeyException;
  4. import java.security.NoSuchAlgorithmException;
  5. import javax.crypto.BadPaddingException;
  6. import javax.crypto.Cipher;
  7. import javax.crypto.IllegalBlockSizeException;
  8. import javax.crypto.NoSuchPaddingException;
  9. import javax.crypto.SecretKey;
  10. import javax.crypto.spec.IvParameterSpec;
  11. import javax.crypto.spec.SecretKeySpec;
  12. public final class AesCryptoPreSharedKey {
  13. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  14. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant cr
  15. iteria), including algorithms, block cipher modes, and padding modes.
  16. // Parameters passed to getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule
  17. // In this sample, we choose the following parameter values: encryption algorithm=AES, block encryption mode=CBC, padding rule=PKCS7Padding
  18. private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";
  19. // Encryption algorithm
  20. private static final String KEY_ALGORITHM = "AES";
  21. // Length of IV in bytes
  22. public static final int IV_LENGTH_BYTES = 16;
  23. // *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption
  24. // Check the length of the key
  25. private static final int MIN_KEY_LENGTH_BYTES = 16;
  26. private byte[] mIV = null;
  27. public byte[] getIV() {
  28. return mIV;
  29. }
  30. AesCryptoPreSharedKey(final byte[] iv) {
  31. mIV = iv;
  32. }
  33. AesCryptoPreSharedKey() {
  34. }
  35. public final byte[] encrypt(final byte[] keyData, final byte[] plain) {
  36. byte[] encrypted = null;
  37. try {
  38. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  39. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  40. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  41. SecretKey secretKey = generateKey(keyData);
  42. if (secretKey != null) {
  43. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  44. mIV = cipher.getIV();
  45. encrypted = cipher.doFinal(plain);
  46. }
  47. } catch (NoSuchAlgorithmException e) {
  48. } catch (NoSuchPaddingException e) {
  49. } catch (InvalidKeyException e) {
  50. } catch (IllegalBlockSizeException e) {
  51. } catch (BadPaddingException e) {
  52. } finally {
  53. }
  54. return encrypted;
  55. }
  56. public final byte[] decrypt(final byte[] keyData, final byte[] encrypted) {
  57. byte[] plain = null;
  58. try {
  59. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  60. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  61. Cipher cipher = Cipher.getInstance(TRANSFORMATION);
  62. SecretKey secretKey = generateKey(keyData);
  63. if (secretKey != null) {
  64. IvParameterSpec ivParameterSpec = new IvParameterSpec(mIV);
  65. cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
  66. plain = cipher.doFinal(encrypted);
  67. }
  68. } catch (NoSuchAlgorithmException e) {
  69. } catch (NoSuchPaddingException e) {
  70. } catch (InvalidKeyException e) {
  71. } catch (InvalidAlgorithmParameterException e) {
  72. } catch (IllegalBlockSizeException e) {
  73. } catch (BadPaddingException e) {
  74. } finally {
  75. }
  76. return plain;
  77. }
  78. private static final SecretKey generateKey(final byte[] keyData) {
  79. SecretKey secretKey = null;
  80. try {
  81. // *** POINT 3 *** Use a key of length sufficient to guarantee the strength of encryption
  82. if (keyData.length >= MIN_KEY_LENGTH_BYTES) {
  83. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  84. secretKey = new SecretKeySpec(keyData, KEY_ALGORITHM);
  85. }
  86. } catch (IllegalArgumentException e) {
  87. } finally {
  88. }
  89. return secretKey;
  90. }
  91. }

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

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

要点:

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

HmacPBEKey.java

  1. package org.jssec.android.signsymmetricpasswordbasedkey;
  2. import java.security.InvalidKeyException;
  3. import java.security.NoSuchAlgorithmException;
  4. import java.security.SecureRandom;
  5. import java.security.spec.InvalidKeySpecException;
  6. import java.util.Arrays;
  7. import javax.crypto.Mac;
  8. import javax.crypto.SecretKey;
  9. import javax.crypto.SecretKeyFactory;
  10. import javax.crypto.spec.PBEKeySpec;
  11. public final class HmacPBEKey {
  12. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  13. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  14. // Parameters passed to the getInstance method of the Mac class: Authentication mode
  15. private static final String TRANSFORMATION = "PBEWITHHMACSHA1";
  16. // A string used to fetch an instance of the class that generates the key
  17. private static final String KEY_GENERATOR_MODE = "PBEWITHHMACSHA1";
  18. // *** POINT 3 *** When generating a key from a password, use Salt.
  19. // Salt length in bytes
  20. public static final int SALT_LENGTH_BYTES = 20;
  21. // *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.
  22. // Set the number of mixing repetitions used when generating keys via PBE
  23. private static final int KEY_GEN_ITERATION_COUNT = 1024;
  24. // *** POINT 5 *** Use a key of length sufficient to guarantee the MAC strength.
  25. // Key length in bits
  26. private static final int KEY_LENGTH_BITS = 160;
  27. private byte[] mSalt = null;
  28. public byte[] getSalt() {
  29. return mSalt;
  30. }
  31. HmacPBEKey() {
  32. initSalt();
  33. }
  34. HmacPBEKey(final byte[] salt) {
  35. mSalt = salt;
  36. }
  37. private void initSalt() {
  38. mSalt = new byte[SALT_LENGTH_BYTES];
  39. SecureRandom sr = new SecureRandom();
  40. sr.nextBytes(mSalt);
  41. }
  42. public final byte[] sign(final byte[] plain, final char[] password) {
  43. return calculate(plain, password);
  44. }
  45. private final byte[] calculate(final byte[] plain, final char[] password) {
  46. byte[] hmac = null;
  47. try {
  48. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  49. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  50. Mac mac = Mac.getInstance(TRANSFORMATION);
  51. // *** POINT 3 *** When generating a key from a password, use Salt.
  52. SecretKey secretKey = generateKey(password, mSalt);
  53. mac.init(secretKey);
  54. hmac = mac.doFinal(plain);
  55. } catch (NoSuchAlgorithmException e) {
  56. } catch (InvalidKeyException e) {
  57. } finally {
  58. }
  59. return hmac;
  60. }
  61. public final boolean verify(final byte[] hmac, final byte[] plain, final char[] password) {
  62. byte[] hmacForPlain = calculate(plain, password);
  63. if (Arrays.equals(hmac, hmacForPlain)) {
  64. return true;
  65. }
  66. return false;
  67. }
  68. private static final SecretKey generateKey(final char[] password, final byte[] salt) {
  69. SecretKey secretKey = null;
  70. PBEKeySpec keySpec = null;
  71. try {
  72. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  73. // Fetch an instance of the class that generates the key
  74. // In this example, we use a KeyFactory that uses SHA1 to generate AES-CBC 128-bit keys.
  75. SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);
  76. // *** POINT 3 *** When generating a key from a password, use Salt.
  77. // *** POINT 4 *** When generating a key from a password, specify an appropriate hash iteration count.
  78. // *** POINT 5 *** Use a key of length sufficient to guarantee the MAC strength.
  79. keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);
  80. // Clear password
  81. Arrays.fill(password, '?');
  82. // Generate the key
  83. secretKey = secretKeyFactory.generateSecret(keySpec);
  84. } catch (NoSuchAlgorithmException e) {
  85. } catch (InvalidKeySpecException e) {
  86. } finally {
  87. keySpec.clearPassword();
  88. }
  89. return secretKey;
  90. }
  91. }

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

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

要点:

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

RsaSignAsymmetricKey.java

  1. package org.jssec.android.signasymmetrickey;
  2. import java.security.InvalidKeyException;
  3. import java.security.KeyFactory;
  4. import java.security.NoSuchAlgorithmException;
  5. import java.security.PrivateKey;
  6. import java.security.PublicKey;
  7. import java.security.Signature;
  8. import java.security.SignatureException;
  9. import java.security.interfaces.RSAPublicKey;
  10. import java.security.spec.InvalidKeySpecException;
  11. import java.security.spec.PKCS8EncodedKeySpec;
  12. import java.security.spec.X509EncodedKeySpec;
  13. public final class RsaSignAsymmetricKey {
  14. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  15. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  16. // Parameters passed to the getInstance method of the Cipher class: Encryption algorithm, block encryption mode, padding rule
  17. // In this sample, we choose the following parameter values: encryption algorithm=RSA, block encryption mode=NONE, padding rule=OAEPPADDING.
  18. private static final String TRANSFORMATION = "SHA256withRSA";
  19. // encryption algorithm
  20. private static final String KEY_ALGORITHM = "RSA";
  21. // *** POINT 3 *** Use a key of length sufficient to guarantee the signature strength.
  22. // Check the length of the key
  23. private static final int MIN_KEY_LENGTH = 2000;
  24. RsaSignAsymmetricKey() {
  25. }
  26. public final byte[] sign(final byte[] plain, final byte[] keyData) {
  27. // In general, signature procedures should be implemented on the server side;
  28. // however, in this sample code we have implemented signature processing within the application to ensure confirmation of proper execution.
  29. // When using this sample code in real-world applications, be careful not to retain any private keys within the application.
  30. byte[] sign = null;
  31. try {
  32. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  33. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  34. Signature signature = Signature.getInstance(TRANSFORMATION);
  35. PrivateKey privateKey = generatePriKey(keyData);
  36. signature.initSign(privateKey);
  37. signature.update(plain);
  38. sign = signature.sign();
  39. } catch (NoSuchAlgorithmException e) {
  40. } catch (InvalidKeyException e) {
  41. } catch (SignatureException e) {
  42. } finally {
  43. }
  44. return sign;
  45. }
  46. public final boolean verify(final byte[] sign, final byte[] plain, final byte[] keyData) {
  47. boolean ret = false;
  48. try {
  49. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  50. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  51. Signature signature = Signature.getInstance(TRANSFORMATION);
  52. PublicKey publicKey = generatePubKey(keyData);
  53. signature.initVerify(publicKey);
  54. signature.update(plain);
  55. ret = signature.verify(sign);
  56. } catch (NoSuchAlgorithmException e) {
  57. } catch (InvalidKeyException e) {
  58. } catch (SignatureException e) {
  59. } finally {
  60. }
  61. return ret;
  62. }
  63. private static final PublicKey generatePubKey(final byte[] keyData) {
  64. PublicKey publicKey = null;
  65. KeyFactory keyFactory = null;
  66. try {
  67. keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  68. publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyData));
  69. } catch (IllegalArgumentException e) {
  70. } catch (NoSuchAlgorithmException e) {
  71. } catch (InvalidKeySpecException e) {
  72. } finally {
  73. }
  74. // *** POINT 3 *** Use a key of length sufficient to guarantee the signature strength.
  75. // Check the length of the key
  76. if (publicKey instanceof RSAPublicKey) {
  77. int len = ((RSAPublicKey) publicKey).getModulus().bitLength();
  78. if (len < MIN_KEY_LENGTH) {
  79. publicKey = null;
  80. }
  81. }
  82. return publicKey;
  83. }
  84. private static final PrivateKey generatePriKey(final byte[] keyData) {
  85. PrivateKey privateKey = null;
  86. KeyFactory keyFactory = null;
  87. try {
  88. keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  89. privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyData));
  90. } catch (IllegalArgumentException e) {
  91. } catch (NoSuchAlgorithmException e) {
  92. } catch (InvalidKeySpecException e) {
  93. } finally {
  94. }
  95. return privateKey;
  96. }
  97. }

5.6.1.6 使用预共享密钥来检测数据伪造

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

要点:

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

HmacPreSharedKey.java

  1. package org.jssec.android.signsymmetricpresharedkey;
  2. import java.security.InvalidKeyException;
  3. import java.security.NoSuchAlgorithmException;
  4. import java.util.Arrays;
  5. import javax.crypto.Mac;
  6. import javax.crypto.SecretKey;
  7. import javax.crypto.spec.SecretKeySpec;
  8. public final class HmacPreSharedKey {
  9. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  10. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  11. // Parameters passed to the getInstance method of the Mac class: Authentication mode
  12. private static final String TRANSFORMATION = "HmacSHA256";
  13. // Encryption algorithm
  14. private static final String KEY_ALGORITHM = "HmacSHA256";
  15. // *** POINT 3 *** Use a key of length sufficient to guarantee the MAC strength.
  16. // Check the length of the key
  17. private static final int MIN_KEY_LENGTH_BYTES = 16;
  18. HmacPreSharedKey() {
  19. }
  20. public final byte[] sign(final byte[] plain, final byte[] keyData) {
  21. return calculate(plain, keyData);
  22. }
  23. public final byte[] calculate(final byte[] plain, final byte[] keyData) {
  24. byte[] hmac = null;
  25. try {
  26. // *** POINT 1 *** Explicitly specify the encryption mode and the padding.
  27. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  28. Mac mac = Mac.getInstance(TRANSFORMATION);
  29. SecretKey secretKey = generateKey(keyData);
  30. if (secretKey != null) {
  31. mac.init(secretKey);
  32. hmac = mac.doFinal(plain);
  33. }
  34. } catch (NoSuchAlgorithmException e) {
  35. } catch (InvalidKeyException e) {
  36. } finally {
  37. }
  38. return hmac;
  39. }
  40. public final boolean verify(final byte[] hmac, final byte[] plain, final byte[] keyData) {
  41. byte[] hmacForPlain = calculate(plain, keyData);
  42. if (hmacForPlain != null && Arrays.equals(hmac, hmacForPlain)) {
  43. return true;
  44. }
  45. return false;
  46. }
  47. private static final SecretKey generateKey(final byte[] keyData) {
  48. SecretKey secretKey = null;
  49. try {
  50. // *** POINT 3 *** Use a key of length sufficient to guarantee the MAC strength.
  51. if (keyData.length >= MIN_KEY_LENGTH_BYTES) {
  52. // *** POINT 2 *** Use strong encryption methods (specifically, technologies that meet the relevant criteria), including algorithms, block cipher modes, and padding modes.
  53. secretKey = new SecretKeySpec(keyData, KEY_ALGORITHM);
  54. }
  55. } catch (IllegalArgumentException e) {
  56. } finally {
  57. }
  58. return secretKey;
  59. }
  60. }