Java实现7种常见密码算法( 四 )


JCA密钥相关类关系一览 , 如下:

Java实现7种常见密码算法

文章插图
Java实现7种常见密码算法

文章插图
常见问题密文无法解密问题有时 , 在使用密码算法时 , 会发现别人提供的密文使用正确的密钥却无法解密出来 , 特别容易发生在跨语言的情况下 , 如加密方使用的C#语言 , 而解密方却使用的Java 。
遇到这种情况 , 你需要和对方认真确认加密时使用的加密模式、填充模式以及IV等密码参数是否完全一致 。
如AES算法加密模式有ECBCBCCFBCTRGCM等 , 填充模式有PKCS#5, ISO 10126, ANSI X9.23等 , 以及对方是使用了固定的IV向量还是将IV向量拼在了密文中 , 这些都需要确认清楚并与对方保持一致才能正确解密 。
签名失败问题签名失败也是使用密码算法时常见的情况 , 比如对方生成的MD5值与你生成的MD5不一致 , 常见有2种原因 , 如下:1. 使用的字符编码不一致导致密码算法为了通用性 , 操作对象都是字节数组 , 而你要签名的对象一般是字符串 , 因此你需要将字符串转为字节数组之后再做md5运算 , 如下:
  • 调用方:md5(str.getBytes())
  • 服务方:md5(str.getBytes())
看起来两边的代码一模一样 , 但问题就在getBytes()函数中 , getBytes()函数默认会使用操作系统的字符编码将字符串转为字节数组 , 而中文Windows默认字符编码是GBK , 而Linux默认是UTF-8 , 这就导致当str中有中文时 , 调用方与服务方获取到的字节数组是不一样的 , 那生成的MD5值当然也不一样了 。
因此 , 强烈推荐在使用getBytes()函数时 , 传入统一的字符编码 , 如下:
  • 调用方:md5(str.getBytes("UTF-8"))
  • 服务方:md5(str.getBytes("UTF-8"))这样就能有效地避过这个非常隐晦的坑了 。
2. json的escape功能导致有些json框架 , 做json序列化时会默认做一些转义操作 , 如把&字符转义为\u0026 , 但如果服务端做json反序列化时没有做反转义 , 这会导致两边计算的签名值不一样 , 如下:
  • 调用方:md5("&")
  • 服务方:md5("\\u0026")这也是一个非常隐晦的坑 , 如Gson默认就会有这种行为 , 可使用new GsonBuilder().disableHtmlEscaping()禁用 。
生成与读取证书概念随着对密码学了解的深入 , 会发现有特别多奇怪的名词出现 , 让人迷惑不已 , 如PKCS8X.509ASN.1DERPEM等 , 接下来就来澄清下这些名词是什么 , 以及它们之间的关系 。
首先 , 了解3个概念 , 如下:
  • 密钥:包括对称密钥与非对称密钥等 。
  • 证书:包含用户或网站的身份信息、公钥 , 以及CA的签名 。
  • 密钥库:用于存储密钥与证书的仓库 。
ASN.1语法ASN.1抽象语法标记(Abstract Syntax Notation One) , 和XML、JSON类似 , 用于描述对象结构 , 可以把它看成一种描述语言 , 简单的示例如下:

经验总结扩展阅读