安卓應用安全指南 5.6.1 密碼學 示例程式碼
5.6.1 密碼學 示例程式碼
原書:Android Application Secure Design/Secure Coding Guidebook
譯者:飛龍
針對特定用途和條件開發了各種加密方法,包括加密和解密資料(來確保機密性)和檢測資料偽造(來確保完整性)等用例。 以下是示例程式碼,根據每種技術的目的分為三大類加密技術。 在每種情況下,應該能夠根據密碼技術的特點,選擇適當的加密方法和金鑰型別。 對於需要更詳細考慮的情況,請參見章節“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=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 使用公鑰的加密和解密
在某些情況下,資料加密僅在應用端使用儲存的公鑰來執行,而解密在單獨安全位置(如伺服器)在私鑰下執行。 在這種情況下,可以使用公鑰(非對稱金鑰)加密。
要點:
- 顯式指定加密模式和填充
- 使用強加密方法(特別是符合相關標準的技術),包括演算法,分組加密模式和填充模式。
- 使用足以保證加密強度的金鑰長度。
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 使用預共享金鑰的加密和解密
預共享金鑰可用於處理大型資料集,或保護應用或使用者資產的機密性。
要點:
- 顯式指定加密模式和填充
- 使用強加密方法(特別是符合相關標準的技術),包括演算法,分組加密模式和填充模式。
- 使用足以保證加密強度的金鑰長度。
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 使用基於密碼的金鑰來檢測資料偽造
你可以使用基於密碼的(共享金鑰)加密來驗證使用者資料的完整性。
要點:
- 顯式指定加密模式和填充。
- 使用強加密方法(特別是符合相關標準的技術),包括演算法,分組加密模式和填充模式。
- 從密碼生成金鑰時,使用鹽。
- 從密碼生成金鑰時,指定適當的雜湊迭代計數。
- 使用足以保證 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 使用公鑰來檢測資料偽造
所處理的資料的簽名,由儲存在不同的安全位置(如伺服器)中的私鑰確定時,你可以使用公鑰(不對稱金鑰)加密來處理涉及應用端公鑰儲存的應用,出於驗證資料簽名的目的。
要點:
- 顯式指定加密模式和填充。
- 使用強加密方法(特別是符合相關標準的技術),包括演算法,分組加密模式和填充模式。
- 使用足以保證簽名強度的金鑰長度。
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 使用預共享金鑰來檢測資料偽造
你可以使用預共享金鑰來驗證應用資產或使用者資產的完整性。
要點:
- 顯式指定加密模式和填充。
- 使用強加密方法(特別是符合相關標準的技術),包括演算法,分組加密模式和填充模式。
- 使用足以保證 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;
}
}
相關文章
- 安卓應用安全指南4.1.1建立/使用活動示例程式碼安卓
- 安卓應用安全指南4.6.1處理檔案示例程式碼安卓
- 安卓應用安全指南4.3.1建立/使用內容供應器示例程式碼安卓
- 安卓應用安全指南5.4.1通過HTTPS的通訊示例程式碼安卓HTTP
- 安卓應用安全指南翻譯完成安卓
- 應用密碼學——古典密碼密碼學
- 安卓應用安全指南4.8輸出到LogCat安卓GC
- 應用密碼學 - 公鑰密碼密碼學
- 應用密碼學——分組密碼密碼學
- appium 安卓應用指令碼APP安卓指令碼
- 從密碼學到網路安全應用密碼學
- 安卓應用安全指南六、困難問題安卓
- 安卓應用安全指南4.5.2使用SQLite規則書安卓SQLite
- 安卓移動應用程式碼安全加固系統設計及實現安卓
- PKCS#11:密碼裝置與應用程式的密碼學介面密碼學
- 安卓應用安全指南4.1.2建立/使用活動規則書安卓
- 安卓應用安全指南4.7使用可瀏覽的意圖安卓
- 安卓實現賬號密碼儲存安卓密碼
- 安卓應用安全指南5.5.2處理隱私資料規則書安卓
- 密碼學與密碼安全:理論與實踐密碼學
- 鴻蒙Next安全之應用加密:保障應用程式碼安全鴻蒙加密
- 安卓應用安全指南4.2.3建立/使用廣播接收器高階話題安卓
- 密碼學承諾原理與應用 - 概覽密碼學
- 原始碼開放:WebSocket應用示例原始碼Web
- 密碼學之安全模型總結密碼學模型
- vivo手機安裝應用自動輸入密碼密碼
- 歸約證明在密碼學中的應用密碼學
- 密碼安全加固密碼
- PG密碼安全密碼
- MySQL密碼安全MySql密碼
- 驗證碼簡訊 API 接入指南:Java 語言示例程式碼APIJava
- 密碼安全:密碼設定要求,密碼爆破辦法,密碼歸類使用,密碼處置方案密碼
- 程式碼測試用例指南
- 安全防護密碼學之網站安全公司密碼學網站
- 密碼學之前後向安全性密碼學
- 排序程式碼示例排序
- RabbitMQ 程式碼示例MQ
- 管理(002):建立密碼檔案示例密碼