zoukankan      html  css  js  c++  java
  • RSA签名与验签

    RSA签名与验签

    之前看过RSA加密算法的一些介绍,对RSA加密的原理有一些了解。其实刚刚挺熟非对称加密时是觉得很神奇的。通常对称加密很好理解,比如原理是ANA,我们将每个字母后移一位,那么就是BOB了,这就是很简单的加密过程(上帝ana就变成了凡人bob了,只有dota玩家才知道的梗)。解密就将每个字母前移一位。如果把移动的位数看成密钥,那么密钥就是1。加密和解密密钥是一样的。

    刚好最近项目中使了RSA签名,在此记录下。

    项目使用

    目前项目中是使用RSA的签名与验签功能。第三方发送文件给我们,同时会发送该文件的摘要(SHA256)信息,而摘要信息是使用私钥签名过的。我们将收到的文件做摘要(SHA256),然后使用公钥进行验签。如果签名验证通过才能认为文件是可信的。

    问题

    项目组的同事在开发好后想测试一下,但是发现第三方只提供了一个样例文件,而且文件内容还是不符合业务要求的。没办法验证整个流程。

    其实解决方式很简单:替换公钥

    生成密钥对

    第三方提供的公钥是一个没有后缀名的文件,使用文本编辑器打开是乱码的,可以猜测是二进制文件。看了第三方提供的代码,是直接从文件中读取byte数据,然后构建一个PublicKey。

    然后我尝试生成自己的密钥对,一开始我使用的是Xshell。因为SSH是支持RSA加密的,一般的SSH工具都支持生成RSA密钥。

    Xshell

    1. 打开Xshell

    2. 点击“工具”菜单

    3. 点击“新建用户密钥生成向导”

    4. 密钥类型选“RSA”,密钥长度选1024(第三方给的密钥是1024位)

    5. 然后一路下一步,其中,会让输入“用户密钥加密的密码”,我因为是代码中使用,直接没输入。如果是作为SSH登陆的话还是需要输入一下,不然私钥被别人盗用,没有密码,别人就可以为所欲为了。

    6. 然后密钥就生成好了,提供和三种格式的公钥:“SSH1”、“SSH2-IETF SECSH”、“SSH2-OpenSSH”,除了SSH1,SSH2的都是一样的形式只是备注不一样

    生成后发现没法使用,因为Xshell生成的密钥是字符串(Base64编码),类似下面的。

    AAAAB3NzaC1yc2EAAAABIwAAAIEAnfJxPq3OLqfZVt+YNH6tkO7d5qx8etFU8g7adwFzTwuXOaDtm0qoQXMkiRLTt3p5S6ExWM9+NLQePhbSur0d8d6Y4sf3SNB/oIpAYIezkihFczuxHBi1RVNUdVwLdWyFW69eWBGkyaRyt7q0kzIPXMpRz/Gj+JTP45MaNOapW5U=
    

    我通过代码将这个字符串Base64解码成byte数组。然后构建一个公钥,抛出异常。

    Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
    	at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
    	at io.github.loanon.rsa.RSAStudy.main(RSAStudy.java:17)
    Caused by: java.security.InvalidKeyException: invalid key format
    	at sun.security.x509.X509Key.decode(X509Key.java:387)
    	at sun.security.x509.X509Key.decode(X509Key.java:403)
    	at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:84)
    	at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
    	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
    	... 2 more
    

    关键词“invalid key format”让我觉得是密钥格式不对。

    我从网上找了其他RSA的教程,看到别人的密钥(Base64)字符串都是这样的:

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqPvovSfXcwBbW8cKMCgwqNpsYuzF8RPAPFb7LGsnVo44JhM/xxzDyzoYtdfNmtbIuKVi9PzIsyp6rg+09gbuI6UGwBZ5DWBDBMqv5MPdOF5dCQkB2Bbr5yPfURPENypUz+pBFBg41d+BC+rwRiXELwKy7Y9caD/MtJyHydj8OUwIDAQAB
    

    首先从长度上就和我用Xshell生成的不一样。为了验证我的猜想。我将第三方提供的密钥二进制文件读出来,通过Base64编码后,打印出来,和网上别人教程里面的格式、长度一样(这里就不贴出来了)。那么就说明不能用Xshell来生成密钥对。个人认为是密钥格式不通,至于如何转换,还没弄明白。有知道的大神,还请指教一二。

    Java

    既然Xshell工具生成的密钥对不用用,那就自己用Java代码生成,网上也有教程。总结一下:

    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    keyPairGen.initialize(1024);
    KeyPair keyPair = keyPairGen.generateKeyPair();
    byte[] publicKey = keyPair.getPublic().getEncoded();
    byte[] privateKey = keyPair.getPrivate().getEncoded();
    

    这样就可以拿到密钥对的二进制数据了。

    将公钥数据保存成二进制文件,放到项目中。现在就可以自己签名进行验证了。

    密钥格式

    找到一篇文章好像解释了为什么Xshell生成的密钥对无法使用。

    因为Xshell生成的是OpenSSH格式的密钥,但是Java代码中使用的是OpenSSL格式的密钥。其实通过代码或者工具也是可以将两种格式的密钥进行转换的。

  • 相关阅读:
    大型网站技术架构:核心原理与案例分析笔记
    Springmvc 中org.springframework.http.converter.json.MappingJackson2HttpMessageConverter依赖jackson包
    idea 打开自动编译以及查看Problem窗口
    idea出现Error:Maven Resources Compiler: Maven project configuration required for module 'market' isn't available.
    Git常用命令
    mysql explain用法
    mysql中insert into select from的使用
    SpringMVC使用@PathVariable,@RequestBody,@ResponseBody,@RequestParam,@InitBinder
    git创建仓库
    context:component-scan扫描使用的use-default-filters
  • 原文地址:https://www.cnblogs.com/jimmyfan/p/11810226.html
Copyright © 2011-2022 走看看