必须显式指定模式和填充,如"AES/GCM/NoPadding";ECB不安全且默认填充兼容性差,密钥须为16/24/32字节二进制数据,不可直接用字符串。

Java里用AES加密密码时,Cipher.getInstance("AES")为什么总抛InvalidKeyException
因为默认没指定模式和填充,JVM会挑一个不兼容你密钥长度或平台默认策略的组合。OpenJDK 17+ 默认禁用弱算法,且AES裸写等价于AES/ECB/PKCS5Padding,而ECB不安全、PKCS5Padding在部分JRE里实际映射到PKCS7,密钥长度不对(比如用了128位但传了16字节字符串没对齐)就直接炸。
- 必须显式写全:
Cipher.getInstance("AES/GCM/NoPadding")(推荐)或AES/CBC/PKCS5Padding - GCM需要12字节IV(通常用
SecureRandom生成),且SecretKeySpec构造时密钥必须是16/24/32字节,别直接用"mykey123"这种字符串——要用MessageDigest哈希再截取 - Android API
把加密后的密码写进文件后,下次读出来解密失败,错误是BadPaddingException
这不是密码错,是数据在保存/加载过程中被破坏了。最常见的是把二进制密文当文本用String存——比如用FileWriter直接写byte[],或者用Base64.getEncoder().encodeToString()之后又多做了一次UTF-8编码。
- 密文永远走二进制流:
Files.write(path, cipher.doFinal(plainBytes)) - 如果非要存文本(比如配置文件),只做一次Base64编码,且读取时用
Base64.getDecoder().decode()原样还原,中间别碰new String(...)或.getBytes() - 检查文件是否被编辑器“优化”过:Windows记事本、VS Code默认可能加BOM或换行符,用
xxd或十六进制查看器确认开头是不是你预期的密文字节
Java怎么把生成的密码自动塞进系统剪贴板,又不让其他程序偷偷读走
Java的SystemClipBoard本身不加密也不隔离,只要进程有权限就能读。所谓“安全剪贴板”只能靠短时效+主动清空,不是靠机制锁住。
- 用
StringSelection设值后,立刻起个Timer或ScheduledExecutorService,3秒后执行clipboard.setContents(new StringSelection(""), null) - 别用
awt.Toolkit.getDefaultToolkit().getSystemClipboard()在Swing线程外调用,容易报HeadlessException或粘贴失败——确保在EDT里操作 - macOS上Java剪贴板对某些沙盒App(如iTerm2)不可见,这是系统限制,换
pbcopy命令行工具也一样受限
生成密码时用SecureRandom还是Random,差在哪
Random是伪随机,种子可预测;SecureRandom才真正从操作系统熵池取数,适合密钥、盐值、一次性密码。但注意它初始化慢,别每次生成密码都新建一个实例。
- 全局复用一个
SecureRandom单例:private static final SecureRandom SECURE_RANDOM = new SecureRandom(); - 生成密码字符时,不要用
random.nextInt(chars.length)直接索引——如果chars长度不是2的幂,会有轻微偏差;用random.nextInt(256) % chars.length更糟,会严重倾斜;正确做法是循环重试直到结果落在有效范围内 - Android上
SecureRandom.getInstance("SHA1PRNG")在旧版本有bug,直接用无参构造即可
密钥派生、IV生成、密码字符采样,三处都得用SecureRandom,少一处就等于把锁换成挂锁。GCM模式下还要额外校验Tag长度是否为128位,这个点很容易被忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











