messagedigest.getinstance("md5") 抛出 nosuchalgorithmexception 是因算法名大小写敏感且必须为标准jca注册名“md5”(全大写),小写“md5”或非标准名如“md5sum”均不被接受。

MessageDigest.getInstance("MD5") 为什么抛出 NoSuchAlgorithmException
Java 的 MessageDigest 是标准 API,但算法名大小写敏感且必须是 JCA 注册名称。常见错误是传 "md5"(小写)或 "MD5sum" 这类非标准字符串。
- 只接受
"MD5"(全大写),不区分平台,JDK 8+ 均支持 - 别用
"md5"—— 某些旧 Android 版本会失败,OpenJDK 和 Oracle JDK 也非强制兼容小写 - 不需要手动注册算法,但若在受限安全策略环境(如某些 Applet 或沙箱)中运行,需确认
java.security.Security允许该算法
byte[] 转 hex 字符串时为什么出现负数或乱码
MessageDigest.digest() 返回的是原始字节数组,每个 byte 是有符号的(-128 ~ 127)。直接用 String.valueOf(byte) 或 new String(byte[]) 会把负值当字符解释,结果不可读、不可比。
- 必须逐字节转为无符号十六进制:用
(b & 0xFF)掩码消除符号位 - 避免用
BigInteger构造 hex —— 它会自动去掉前导零,导致 16 字节 MD5 变成 31 位甚至更短字符串(比如00000000000000000000000000000001变成1) - 推荐用
String.format("%02x", b & 0xFF)或Hex.encodeHexString()(Apache Commons Codec),前者零依赖,后者更健壮
MD5 不加盐直接哈希密码为什么危险
MD5 本身计算极快,现代 GPU 一秒可尝试上亿次。裸 MD5 对密码毫无防护力,彩虹表可直接查出常见口令。
- 不要对密码单独调用
MessageDigest.digest()后存库 - 即使加一次盐,也远不如用
PBKDF2WithHmacSHA256+ 10万轮迭代(SecretKeyFactory实现) - 如果只是校验文件完整性或生成唯一标识(非安全场景),裸 MD5 可用,但注意 JDK 9+ 默认禁用 MD5 在 TLS 中的使用,不影响本地计算
Android 上 MessageDigest.getInstance("MD5") 返回 null 怎么办
这不是 Java 层问题,而是部分低版本 Android(尤其是 4.x 系统)在某些厂商 ROM 中,Security.getProviders() 可能未正确加载 SunJCE 提供者,导致 getInstance 返回 null 而非抛异常。
立即学习“Java免费学习笔记(深入)”;
- 改用
MessageDigest.getInstance("MD5", "SUN")显式指定 provider(仅限有SUN提供者的环境) - 更稳妥做法:捕获
NullPointerException后 fallback 到"BC"(Bouncy Castle),前提是已集成 BC 库 - 实际开发中建议直接用
android.util.Base64配合自定义 hex 工具类,避开 provider 争议
MD5 的真正陷阱不在写法,而在误把它当安全方案用。哪怕 hex 转换写对了,只要拿它存密码、做签名、防篡改,逻辑上就已经失效了。真要加密,得看场景选对算法;真要校验,至少加个随机 salt 再哈希——而这些,MessageDigest 本身一个都不管。










