安卓开发中手机号一键登入,需要得到本机号码,号码有三大运营商,所以用的时极光平台,帮我们封装好了。客户端通过认证Android SDK 后获取loginToken给服务端,服务端拿到loginToken调用一键认证Api获取加密的手机号(基于RSA公钥),需要用对应的RSA私钥解密,但出现了java.security.InvalidKeyException: IOException : DER input, Integer tag error这个问题,意思是私钥格式不对,处理了半天,避免大家踩坑,总结出这篇文章。
对获取到加密的手机号进行解密报的异常,先看官网的解密方案:
官方是使用了RSA的私钥对加密的手机号进行解密,
什么是RSA?
-
计算机中常用的加密技术分为两类:对称加密、非对称加密。
-
RSA属于非对称加密。加密、解密过程使用不同的秘钥,分为公钥、私钥。公钥可以公开,私钥不可以。
-
对称加密:加密和解密使用相同的的秘钥
Key
,这个Key
需要在网络上传输,不安全,因此需要非对称加密
我们服务端通过loginToken获取的手机号就是通过公钥来加密的,需要使用对应的私钥来进行解密,这里提供RSA相关的加解密工具网址 RSA加解密工具
于是我应开发的需求,生成了一对带密码的RSA公私钥对(可以设置无密码,就是随机生成,但我设置了密码,就是这个行为让我报了半天的错误)
为了验证生成的密钥对能否对症成功,我在RSA加解密工具验证的时候,发现需要带密码才能验证成功,可上面是说密码可写可不写,我当时没有在意,就任他发展,让我苦逼的在后面。
我的代码实现1
package com.lyj.biz.converter;import cn.hutool.core.util.CharsetUtil;import cn.hutool.core.util.StrUtil;import cn.hutool.crypto.asymmetric.KeyType;import cn.hutool.crypto.asymmetric.RSA;public class RSATest { public static void main(String[] args) { //RSA私钥 final String JVERIFY_PRIVATE_KEY="MIIC3TBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIM5nBmtpZeEQCAggA" + "MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBQ9OWtLaOumZtlrURZgNjiBIIC" + "gIK6eSC4EUaVGJPzOMTvDEnpsCvPIMpuIgPnpQldlF5z3qhoxVJ9fbYiuSeZuYz7" + "FM50OL2YdfcW2ajY4UcE0OlA+GVPR61fCcvr0PXYrQDjrXVQ24U52kfzxqsRlu4q" + "LnHPdNZwI8FHA5eBp" + "Q6f9xosqFmkhGXoENZV1cxseuT5hhcC6389V5GWG/gmtxy/ff01oHgzi1s5n6BdC" + "9jU9ju2VfwrQn2NxygNARtMajEtWL1/pk4vmtu694zPTv7SJe2bgMPIdh5uH6ZLT" + "dbrJSXLfwaNM39BWYJG4ZzcPl58yE8QqA6+mRkkCwvdV9n/Vs9uwXRHE3DfH1O11" + "ZtQax5TGpEHa+XUdG6p+3ktYJmm2NUoy3ED2bVYX54" + "fDXGh2/tV4wO+ohnpaLY6EaXf0vKWNrSzmUILahx0BcE/MY6Ea6hWemXuJFbxASD" + "Zb4EtYbMsa5/RDAueagGuDzWFOx957/868ZcYUhs9gEozCq8WQ8WCQ6wKHoI3L3W" + "RxQo7ROBDQ/fu0rqvT7Z5h2fMtXbiyybYkoV3TjxQP4RUCypTC2hgKK/owU4/FUG" + "GJzLPRe2jZBeWrlqgVmKo1zLdYu6EOQ/Z7pERUbmIOnXPDWeLx7fxJCCPlSLfVWb" + "5b37YOAZxP98kpR3tm/pXT/dDnZu3j7hmu+kldwajxwY+NNagVqwIfrUs5LOjq58" + "Eq7KcrwvSj0ymufRm13Z2hVFepn+y5W+pDIoTNLl8mBZNI0H3TlsV89NltTvp0TT" + "bUMXPCljfsaXNa2O7DGnVsk="; //RSA公钥 final String JVERIFY_PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADC"+ "BiQKBgQCS5mh332H7gtyJuwWtGk7DEG9J3xejIY23J"+ "0KpGsAUuSV9WrBYasDf"+ "jv6GIUeDCBIo+VxKfYJ2doRI53T3kQ9s"+ "k8N8rvDpLerhYkyD0z0lIhc5pypsW1lgbSoEQOliS/BSdIp6MOFdwIDAQAB"; //加密后的电话号码(RSA加密) String phoneToken = "fVPnF7Ux+s1NNFrJalt+nK4oOjS+CTt/5OUca5aIfBXcfeAouPJ4Bt96iIT91hjpMvAMshixCiuX5NK9he9OrtUfkRf"+ "/mW3veLn75HJ2hQLZwwVAJ9R3AJVXgN1XMU1Kr1tWtEvdo1U1nCR9WNaYp0u4FSnrQijHjAyxMbITwfg="; //返回解密后的电话号码(通过私钥解密) RSA rsa = new RSA(JVERIFY_PRIVATE_KEY, JVERIFY_PUBLIC_KEY); byte[] decrypt = rsa.decrypt(phoneToken, KeyType.PrivateKey); System.out.println(StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8)); }}
结果:
我是通过公钥和私钥一起来对密文进行解密的,结果报错:意思是识别不到你的私钥,不自信的我开始以为是没有使用官方答案,于是我借鉴官网的方案
package com.lyj.biz.converter;import javax.crypto.Cipher;import java.security.KeyFactory;import java.security.PrivateKey;import java.security.spec.PKCS8EncodedKeySpec;import java.util.Base64;public class RSADecrypt {public static void main(String[] args) throws Exception { //加密手机号 String encrypted = "fVPnF7Ux+s1NNFrJalt+nK4oOjS+CTt/5OUca5aIfBXcfeAouPJ4Bt96iIT91hjpMvAMshixCiuX5NK9he9OrtUfkRf/mW3veLn75HJ2hQLZwwVAJ9R3AJVXgN1XMU1Kr1tWtEvdo1U1nCR9WNaYp0u4FSnrQijHjAyxMbITwfg="; //RSA对应私钥 String prikey = "MIIC3TBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIM5nBmtpZeEQCAggA" + "MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBQ9OWtLaOumZtlrURZgNjiBIIC" + "gIK6sCvPIMpuIgPnpQldlF5z3qhoxVJ9fbYiuSeZuYz7" + "FM50OL2YdfcW2ajY4UcE0OlA+GVPR61fCcvr0PXYrQDjrXVQ24U52kfzxqsRlu4q" + "L5muocW0MVe5PIswm9tcwzbx6zIXQAiINyYgtFmNZaIichhMnHPdNZwI8FHA5eBp" + "Q6f9xosqFmkhGXoENZV1cxseuT5hhcC6389V5GWG/gmtxy/ff01oHgzi1s5n6BdC" + "9jU9jvmtu694zPTv7SJe2bgMPIdh5uH6ZLT" + "dbrJSXLfwaNM39BWYJG4ZzcPl58yE8QqA6+mRkkCwvdV9n/Vs9uwXRHE3DfH1O11" + "ZtQakSqY8PKPTMvfahwz9yWrVQx5TGpEHa+XUdG6p+3ktYJmm2NUoy3ED2bVYX54" + "fDXGh2/tV4wO+ohnpaLY6EaXf0vKWNrSzmUILahx0BcE/MY6Ea6hWemXuJFbxASD" + "Zb4EtYbMsa5/RWQ8WCQ6wKHoI3L3W" + "RxQo7ROBDQ/fu0rqvT7Z5h2fMtXbiyybYkoV3TjxQP4RUCypTC2hgKK/owU4/FUG" + "GJzLPRe2jZBeWrlqgVmKo1zLdYu6EOQ/Z7px7fxJCCPlSLfVWb" + "5b37YOAZ+kldwajxwY+NNagVqwIfrUs5LOjq58" + "Eq7KcrwvSj0ymufRm13Z2hVFepn+y5W+pDIoTNLl8mBZNI0H3TlsV89NltTvp0TT" + "bUMXPCljfsaXNa2O7DGnVsk="; String result = decrypt(encrypted, prikey); System.out.println(result);} public static String decrypt(String cryptograph, String prikey) throws Exception { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(prikey)); PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Cipher cipher=Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte [] b = Base64.getDecoder().decode(cryptograph); return new String(cipher.doFinal(b)); }}
结果还是报错
一开始我是纠结是不是我的密钥格式不正确,接着去查又说什么jdk的security版本不兼容了,后面我就研究那个生成工具,意识到可能是设置了密码问题,设置密码后的每次使用几乎都要带上密码,否则就是失败。
于是我抱着尝试的心态,把之前私钥的密码给清除了
运用生成好后的私钥,替换代码中先前的私钥,果然,十分顺畅,完美解决
无论是官方的还是自己的都行的通,成功解密出对应的手机号
如果需要清除RSA密码的可以通过私钥在在线RSA私钥密码添加、修改、清除工具-ME2在线工具 (metools.info)修改删除,公钥主要用于加密,私钥用于解密,所以公钥可以公开,私钥记得妥善保管。
如果碰见和我同样的问题,建议拿到私钥后去RSA在线工具修改清楚掉密码,RSA公私钥对请妥善保管,
来源地址:https://blog.csdn.net/liyingjie2001/article/details/128156745