安卓应用安全指南 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;
}
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
安卓应用安全指南 5.5.2 处理隐私数据 规则书
5.5.2 处理隐私数据 规则书 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0 处理隐私策略时,遵循以下规则: 5.5.2.1 将用户数据的传输限制为最低需求(必需) 将使用数据传输到外部服务器或其他目标时,将传输限制在提供服务的最低需求。 特别是,你应该设计为,应用只能访问这些用户数据,用户可以根据应用描述来想象它们的使用目的。 例如,用户可以想象,它是个警报应用,但不能访问位置数据。另一方面,如果警报应用可以根据用户的位置发出警报,并将其功能写入应用的描述中,则应用可以访问位置数据。 在只需要在应用中访问信息的情况下,避免将信息传输到外部,并采取其他措施来减少无意中泄漏用户数据的可能性。 5.5.2.2 在首次加载(或应用更新)时,获得广泛同意来传输需要特别细致处理或用户可能难以更改的用户数据(必需) 如果应用向外部服务器,传输用户可能难以更改的任何用户数据,或需要特别细致处理的任何用户数据,则应用必须在用户开始使用之前,获得用户的预先同意(选择性加入) -...
-
下一篇
安卓应用安全指南 5.7 使用指纹认证功能
5.7 使用指纹认证功能 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0 目前正在研究和开发的各种用于生物认证的方法中,使用面部信息和声音特征的方法尤其突出。在这些方法中,使用指纹认证来识别个体的方法自古以来就有所使用,并且今天被用于签名(通过拇指印)和犯罪调查等目的。指纹识别的应用也在计算机世界的几个领域中得到了发展,并且近年来,这些方法已经开始作为高度便利的技术(提供诸如易于输入的优点)而享有广泛认可,用于一些领域,例如识别智能手机的物主(主要用于解锁屏幕)。 在这些趋势下,Android 6.0(API Level 23)在终端上整合了指纹认证框架,允许应用使用指纹认证功能来识别个人身份。在下面我们将讨论一些使用指纹认证时要记住的安全预防措施。 5.7.1 示例代码 下面我们提供示例代码,来允许应用使用 Android 的指纹认证功能。 要点: 声明使用USE_FINGERPRINT权限 从AndroidKeyStore供应器获取实例 通知用户需要指纹注册才...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 面试大杂烩
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长