现在比较出名的开源的加密聊天IM是signal,在github开源了很久,而且已经有过万的stars。
其本地消息加密有一套完善的机制,上层我们称为MasterScrect。
说一下使用的这套materscrect这套加密
//获取加密信息
public static MasterSecret getMasterSecret(Context context, String passphrase)
throws InvalidPassphraseException {
try {
//取回整一串保存在本地的加密钥和口令
byte[] encryptedAndMacdMasterSecret = retrieve(context, "master_secret");
//取回口令的盐
byte[] macSalt = retrieve(context, "mac_salt");
//取回迭代次数
int iterations = retrieve(context, "passphrase_iterations", 100);
//验证口令取回加密钥
byte[] encryptedMasterSecret = verifyMac(macSalt, iterations, encryptedAndMacdMasterSecret, passphrase);
//取回加密钥的盐
byte[] encryptionSalt = retrieve(context, "encryption_salt");
//解密密钥(密码为空)
byte[] combinedSecrets = decryptWithPassphrase(encryptionSalt, iterations, encryptedMasterSecret, passphrase);
//加密密钥(密钥串中1~15个字符)
byte[] encryptionSecret = Util.split(combinedSecrets, 16, 20)[0];
//口令密钥(密钥串中16~20个字符)
byte[] macSecret = Util.split(combinedSecrets, 16, 20)[1];
//封装密钥和口令
return new MasterSecret(new SecretKeySpec(encryptionSecret, "AES"),
new SecretKeySpec(macSecret, "HmacSHA1"));
} catch (GeneralSecurityException e) {
Log.w("keyutil", e);
return null; //XXX
} catch (IOException e) {
Log.w("keyutil", e);
return null; //XXX
}
}
再看一下生成密钥的函数,在用户登录的时候会生成一次
public static MasterSecret generateMasterSecret(Context context, String passphrase) {
try {
//生成密钥
byte[] encryptionSecret = generateEncryptionSecret();
//生成口令
byte[] macSecret = generateMacSecret();
//合成字符串密钥
byte[] masterSecret = Util.combine(encryptionSecret, macSecret);
//生成加密盐
byte[] encryptionSalt = generateSalt();
//添加迭代次数
int iterations = generateIterationCount(passphrase, encryptionSalt);
//添加加密盐后加密字符串密钥
byte[] encryptedMasterSecret = encryptWithPassphrase(encryptionSalt, iterations, masterSecret, passphrase);
//添加口令盐
byte[] macSalt = generateSalt();
//添加口令盐后再加密
byte[] encryptedAndMacdMasterSecret = macWithPassphrase(macSalt, iterations, encryptedMasterSecret, passphrase);
//写入SharePreference
save(context, "encryption_salt", encryptionSalt);
save(context, "mac_salt", macSalt);
save(context, "passphrase_iterations", iterations);
save(context, "master_secret", encryptedAndMacdMasterSecret);
save(context, "passphrase_initialized", true);
//通过AES加密密钥,通过哈希口令散列算法加密口令密钥
return new MasterSecret(new SecretKeySpec(encryptionSecret, "AES"),
new SecretKeySpec(macSecret, "HmacSHA1"));
} catch (GeneralSecurityException e) {
Log.w("keyutil", e);
return null;
}
}
1.随机生成AES128位密钥
private static byte[] generateEncryptionSecret() {
try {
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);
SecretKey key = generator.generateKey();
return key.getEncoded();
} catch (NoSuchAlgorithmException ex) {
Log.w("keyutil", ex);
return null;
}
}
2.使用HmacSHA1(哈希口令散列算法)生成随机口令
private static byte[] generateMacSecret() {
try {
KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1");
return generator.generateKey().getEncoded();
} catch (NoSuchAlgorithmException e) {
Log.w("keyutil", e);
return null;
}
}
3.combine是多个字符串合并,只是添加到末尾
4.生成盐,盐是SHA1PRNG生成16位随机字符,添加盐,是添加了冗余来添加混淆复杂度
private static byte[] generateSalt() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
random.nextBytes(salt);
return salt;
}
5.通过不同机型的性能来确定迭代的次数,最少迭代100次,之后通过计算来确定CPU运算能力。
```
private static int generateIterationCount(String passphrase, byte[] salt) {
int TARGET_ITERATION_TIME = 50; //ms
int MINIMUM_ITERATION_COUNT = 100; //default for low-end devices
int BENCHMARK_ITERATION_COUNT = 10000; //baseline starting iteration count
try {
PBEKeySpec keyspec = new PBEKeySpec(passphrase.toCharArray(), salt, BENCHMARK_ITERATION_COUNT);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHA1AND128BITAES-CBC-BC");
//尝试迭代一些字符,来确定CPU运算能力
long startTime = System.currentTimeMillis();