You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
git1/src/java/net/micode/notes/tool/EncryptionUtils.java

250 lines
9.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.tool;
import android.util.Base64;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* 加密工具类提供AES加密/解密、密码哈希生成和验证、密保问题答案哈希生成和验证等功能
*/
public class EncryptionUtils {
private static final String TAG = "EncryptionUtils";
// ====================== 常量定义 ======================
/**
* 加密算法AES/CBC/PKCS7Padding
*/
public static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS7Padding";
/**
* 密钥生成算法PBKDF2WithHmacSHA256
*/
private static final String KEY_GENERATION_ALGORITHM = "PBKDF2WithHmacSHA256";
/**
* 哈希算法SHA-256
*/
private static final String HASH_ALGORITHM = "SHA-256";
/**
* 密钥长度256位
*/
private static final int KEY_LENGTH = 256;
/**
* 盐值长度16字节
*/
private static final int SALT_LENGTH = 16;
/**
* 初始化向量长度16字节
*/
private static final int IV_LENGTH = 16;
/**
* 迭代次数10000
*/
private static final int ITERATION_COUNT = 10000;
// ====================== 工具方法 ======================
/**
* 生成随机盐值
* @return 随机盐值的Base64编码字符串
*/
public static String generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
return Base64.encodeToString(salt, Base64.NO_WRAP);
}
/**
* 生成随机初始化向量
* @return 随机初始化向量的Base64编码字符串
*/
public static String generateIv() {
SecureRandom random = new SecureRandom();
byte[] iv = new byte[IV_LENGTH];
random.nextBytes(iv);
return Base64.encodeToString(iv, Base64.NO_WRAP);
}
/**
* 基于密码和盐值生成密钥
* @param password 密码
* @param salt 盐值的Base64编码字符串
* @return 生成的密钥
* @throws GeneralSecurityException 安全异常
*/
public static SecretKey generateKey(String password, String salt) throws GeneralSecurityException {
byte[] saltBytes = Base64.decode(salt, Base64.NO_WRAP);
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, ITERATION_COUNT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_GENERATION_ALGORITHM);
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
return new SecretKeySpec(keyBytes, "AES");
}
/**
* 加密文本
* @param plainText 明文文本
* @param password 密码
* @param salt 盐值的Base64编码字符串
* @param iv 初始化向量的Base64编码字符串
* @return 加密后的文本的Base64编码字符串
* @throws GeneralSecurityException 安全异常
*/
public static String encrypt(String plainText, String password, String salt, String iv) throws GeneralSecurityException {
SecretKey key = generateKey(password, salt);
byte[] ivBytes = Base64.decode(iv, Base64.NO_WRAP);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));
try {
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP);
} catch (UnsupportedEncodingException e) {
// UTF-8 是标准字符编码,不应该抛出此异常
throw new RuntimeException("UTF-8 encoding not supported", e);
}
}
/**
* 解密文本
* @param encryptedText 加密文本的Base64编码字符串
* @param password 密码
* @param salt 盐值的Base64编码字符串
* @param iv 初始化向量的Base64编码字符串
* @return 解密后的明文文本
* @throws GeneralSecurityException 安全异常
*/
public static String decrypt(String encryptedText, String password, String salt, String iv) throws GeneralSecurityException {
SecretKey key = generateKey(password, salt);
byte[] ivBytes = Base64.decode(iv, Base64.NO_WRAP);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivBytes));
byte[] encryptedBytes = Base64.decode(encryptedText, Base64.NO_WRAP);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
try {
return new String(decryptedBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
// UTF-8 是标准字符编码,不应该抛出此异常
throw new RuntimeException("UTF-8 encoding not supported", e);
}
}
/**
* 生成密码哈希值
* @param password 密码
* @param salt 盐值的Base64编码字符串
* @return 密码哈希值的Base64编码字符串
*/
public static String generatePasswordHash(String password, String salt) {
try {
byte[] saltBytes = Base64.decode(salt, Base64.NO_WRAP);
byte[] passwordBytes = password.getBytes("UTF-8");
// 合并密码和盐值
byte[] combinedBytes = new byte[passwordBytes.length + saltBytes.length];
System.arraycopy(passwordBytes, 0, combinedBytes, 0, passwordBytes.length);
System.arraycopy(saltBytes, 0, combinedBytes, passwordBytes.length, saltBytes.length);
// 计算哈希值
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
byte[] hashBytes = digest.digest(combinedBytes);
return Base64.encodeToString(hashBytes, Base64.NO_WRAP);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Error generating password hash", e);
return null;
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Error generating password hash", e);
return null;
}
}
/**
* 验证密码
* @param password 待验证的密码
* @param salt 盐值的Base64编码字符串
* @param storedHash 存储的哈希值的Base64编码字符串
* @return 密码是否正确
*/
public static boolean verifyPassword(String password, String salt, String storedHash) {
String generatedHash = generatePasswordHash(password, salt);
return generatedHash != null && generatedHash.equals(storedHash);
}
/**
* 生成密保问题答案的哈希值
* @param answer 密保问题答案
* @param salt 盐值的Base64编码字符串
* @return 答案哈希值的Base64编码字符串
*/
public static String generateAnswerHash(String answer, String salt) {
// 转换为小写并去除空格,提高用户体验
String normalizedAnswer = answer.toLowerCase().trim();
return generatePasswordHash(normalizedAnswer, salt);
}
/**
* 验证密保问题答案
* @param answer 待验证的答案
* @param salt 盐值的Base64编码字符串
* @param storedHash 存储的哈希值的Base64编码字符串
* @return 答案是否正确
*/
public static boolean verifyAnswer(String answer, String salt, String storedHash) {
String normalizedAnswer = answer.toLowerCase().trim();
String generatedHash = generatePasswordHash(normalizedAnswer, salt);
return generatedHash != null && generatedHash.equals(storedHash);
}
/**
* 生成随机密钥(用于测试或特殊情况)
* @return 生成的密钥的Base64编码字符串
* @throws NoSuchAlgorithmException 算法不存在异常
*/
public static String generateRandomKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(KEY_LENGTH);
SecretKey key = keyGenerator.generateKey();
return Base64.encodeToString(key.getEncoded(), Base64.NO_WRAP);
}
}