/* * 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); } }