Java安全开发中有三个极易混淆的术语Crypto、Cipher和Password。它们的中文翻译都与“密码”有关但在计算机科学中各自承担着截然不同的角色。Crypto密码学的总称是一个领域或工具箱Cipher加密/解密的具体算法或工具Password用户输入的身份认证凭据理解这三者的区别是写出安全、正确的Java加密代码的第一步。本文将从概念辨析到实战代码带你彻底理清这三个核心概念。回到顶部一、Crypto密码学的总称Crypto是Cryptography密码学 的缩写词源来自希腊语kryptós隐藏/秘密。它是一个宏观概念涵盖了整个密码学领域——包括加密、解密、哈希、数字签名、密钥交换、消息认证码MAC等所有相关技术。在Java中javax.crypto包就是“Crypto”的具体体现。根据官方文档该包“为加密操作提供类和接口”涵盖的操作包括加密、密钥生成和密钥协商、消息认证码MAC生成等。类比理解Crypto就像“厨房”——整个烹饪的场所。里面有不同的区域洗菜、切菜、炒菜、烘焙有各种各样的工具。Crypto ≠ CipherCrypto是整个领域Cipher只是这个领域下的一个具体工具。回到顶部二、CipherJava加密的核心引擎2.1 什么是Cipherjavax.crypto.Cipher是Java加密扩展JCEJava Cryptography Extension框架的核心类提供加密和解密的密码功能。它不保存数据而是执行具体的加解密运算。用官方文档的话说“此类为加密和解密提供密码功能构成了JCE框架的核心。”2.2 Cipher的核心概念Transformation转换模式创建Cipher对象时需要指定一个转换模式Transformation 格式为算法/工作模式/填充模式例如Cipher c Cipher.getInstance(“AES/CBC/PKCS5Padding”);三个组成部分的含义组成部分 说明 示例算法 具体的加密算法 AES、DES、RSA工作模式 分组密码的处理方式仅对分组密码有效 ECB、CBC、GCM、CTR填充模式 数据长度不足块大小时如何补齐 PKCS5Padding、NoPadding工作模式的选择直接影响安全性ECB电子密码本 相同明文生成相同密文不安全不推荐使用CBC密码分组链接 需要随机IV比ECB安全GCM伽罗瓦/计数器模式 AEAD模式同时提供加密和认证现代推荐首选2.3 Cipher的核心方法使用Cipher的标准流程// 1. 创建Cipher实例Cipher cipher Cipher.getInstance(“AES/GCM/NoPadding”);// 2. 初始化指定模式 密钥cipher.init(Cipher.ENCRYPT_MODE, secretKey);// 3. 执行加密/解密byte[] result cipher.doFinal(inputData);关键方法说明getInstance(String transformation)创建Cipher实例init(int opmode, Key key)初始化指定加密/解密模式和密钥update(byte[] input)分块处理数据适用于大数据doFinal(byte[] input)完成加密/解密操作2.4 完整代码示例AES-GCM加密解密import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.security.SecureRandom;import java.util.Base64;public class AesGcmExample {// GCM推荐使用96位12字节IV private static final int GCM_IV_LENGTH 12; private static final int GCM_TAG_LENGTH 128; public static void main(String[] args) throws Exception { // 1. 生成AES密钥256位 KeyGenerator keyGen KeyGenerator.getInstance(AES); keyGen.init(256); SecretKey secretKey keyGen.generateKey(); String plaintext Hello, 这是一个敏感数据; // 2. 加密 byte[] ciphertext encrypt(plaintext, secretKey); System.out.println(密文(Base64): Base64.getEncoder().encodeToString(ciphertext)); // 3. 解密 String decrypted decrypt(ciphertext, secretKey); System.out.println(解密结果: decrypted); } public static byte[] encrypt(String plaintext, SecretKey key) throws Exception { // 生成随机IV byte[] iv new byte[GCM_IV_LENGTH]; SecureRandom.getInstanceStrong().nextBytes(iv); Cipher cipher Cipher.getInstance(AES/GCM/NoPadding); GCMParameterSpec spec new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.ENCRYPT_MODE, key, spec); byte[] ciphertext cipher.doFinal(plaintext.getBytes(UTF-8)); // 将IV和密文合并IV 密文 byte[] result new byte[iv.length ciphertext.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(ciphertext, 0, result, iv.length, ciphertext.length); return result; } public static String decrypt(byte[] encrypted, SecretKey key) throws Exception { // 分离IV和密文 byte[] iv new byte[GCM_IV_LENGTH]; byte[] ciphertext new byte[encrypted.length - GCM_IV_LENGTH]; System.arraycopy(encrypted, 0, iv, 0, GCM_IV_LENGTH); System.arraycopy(encrypted, GCM_IV_LENGTH, ciphertext, 0, ciphertext.length); Cipher cipher Cipher.getInstance(AES/GCM/NoPadding); GCMParameterSpec spec new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.DECRYPT_MODE, key, spec); byte[] plaintext cipher.doFinal(ciphertext); return new String(plaintext, UTF-8); }}注意GCM模式要求每次加密使用不同的IV重复使用IV会引发伪造攻击。回到顶部三、Password用户身份认证的凭据3.1 什么是PasswordPassword口令/密码 是用户用于身份验证的一组字符串。它是“你输入的那个东西”——比如登录系统时输入的mySecret123。3.2 Password与Cipher的本质区别维度 Cipher加密器 Password口令本质 算法/工具 数据/凭据作用 执行加密/解密运算 验证用户身份在代码中 Cipher类的实例 String或char[]变量是否可逆 可逆加密后可解密 不可逆存储存哈希值安全性依赖 算法强度和密钥管理 密码复杂度和存储方式3.3 重要规则Cipher不能直接使用PasswordCipher不接受String类型的Password作为密钥AES算法要求密钥长度必须是16、24或32字节而用户输入的Password如123456长度不固定。必须通过密钥派生函数KDF 将Password转化为固定长度的SecretKey。// ❌ 错误Cipher不能直接使用PasswordString password “mySecret123”;Cipher cipher Cipher.getInstance(“AES/GCM/NoPadding”);cipher.init(Cipher.ENCRYPT_MODE, password); // 编译错误// ✅ 正确通过PBKDF2派生密钥String password “mySecret123”;byte[] salt new byte[16];new SecureRandom().nextBytes(salt);PBEKeySpec spec new PBEKeySpec(password.toCharArray(),salt,10000, // 迭代次数256 // 密钥长度位);SecretKeyFactory factory SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);SecretKey key factory.generateSecret(spec);// 现在key可以作为Cipher的密钥Cipher cipher Cipher.getInstance(“AES/GCM/NoPadding”);cipher.init(Cipher.ENCRYPT_MODE, key);3.4 Password的存储加盐哈希Password绝不能明文存储。正确的做法是使用加盐哈希如bcrypt、Argon2进行不可逆存储。// 使用Spring Security的BCryptBCryptPasswordEncoder encoder new BCryptPasswordEncoder();String hashedPassword encoder.encode(“userPassword”); // 存储此值boolean isValid encoder.matches(“userPassword”, hashedPassword); // 验证回到顶部四、三者关系全景图┌─────────────────────────────────────────────────────────────────┐│ CRYPTO密码学 ││ 整个加密领域的总称 ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ 哈希算法 │ │ 数字签名 │ │ 密钥交换 │ ││ │ (SHA-256) │ │ (RSA) │ │ (DH/ECDH) │ ││ └─────────────┘ └─────────────┘ └─────────────┘ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ CIPHER加密器 │ ││ │ 执行加密/解密运算的具体工具 │ ││ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ ││ │ │ AES │ │ DES │ │ RSA │ │ ││ │ └──────────┘ └──────────┘ └──────────┘ │ ││ └─────────────────────────────────────────────────────────┘ ││ ││ PASSWORD口令 ││ 用户输入的认证凭据 ││ 如“mySecret123”、“hello123” ││ ↓ 通过KDF派生 ││ SecretKey ││ ↓ 交给Cipher ││ 加密/解密 │└─────────────────────────────────────────────────────────────────┘回到顶部五、常见误区与最佳实践误区一把Password直接当密钥用// ❌ 错误String password “123456”;Cipher cipher Cipher.getInstance(“AES”);cipher.init(Cipher.ENCRYPT_MODE, password); // 类型不匹配正确做法使用PBKDF2、bcrypt等KDF将Password派生为密钥。误区二使用ECB模式// ❌ 不安全ECB模式下相同明文产生相同密文Cipher.getInstance(“AES/ECB/PKCS5Padding”);正确做法使用GCM推荐或CBC模式。误区三重复使用IVGCM模式下重复使用IV会引发伪造攻击。每次加密都应生成新的随机IV。最佳实践清单Cipher使用AES/GCM/NoPadding256位密钥IV每次加密生成新的随机IVGCM使用12字节Password存储使用bcrypt或Argon2加盐哈希绝不存储明文Password → 密钥使用PBKDF2WithHmacSHA256迭代次数≥10000密钥管理密钥不得硬编码在代码中应使用密钥管理服务KMS回到顶部六、总结概念 一句话定义 在Java中的体现Crypto 密码学的总称/领域 javax.crypto包Cipher 执行加解密的具体工具 javax.crypto.Cipher类Password 用户身份认证的凭据 String / char[]需加盐哈希存储