http://blog.csdn.net/zhouyuqwert/article/details/8627952

一、DER编码密钥对

先说下DER编码,是因为JCE本身是支持DER编码密钥对的解析的,可以参见PKCS8EncodedKeySpec和X509EncodedKeySpec.

DER编码是ASN.1编码规则中的一个子集,具体格式如何编排没有去了解,但最终呈现肯定的是一堆有规律的二进制组合而成。

PKCS#8定义了私钥信息语法和加密私钥语法,而X509定义证书规范,通常都会用DER和PEM进行编码存储,而在JAVA中则使用的

DER。

接下来看看如果通过DER编码的密钥对分别获取JAVA的公私钥对象。

1.下面一段是生成私钥对象的,传入参数是DER编码的私钥内容。

[java] view plaincopyprint?
  1. @Override
  2. public PrivateKey generatePrivateKey(byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
  3. KeySpec keySpec = new PKCS8EncodedKeySpec(key);
  4. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  5. return keyFactory.generatePrivate(keySpec);
  6. }
 @Override
public PrivateKey generatePrivateKey(byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec keySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}

2.下面是生成公钥对象的,传入参数是DER编码公钥内容,可以看到和生成私钥的部分非常相似。

[java] view plaincopyprint?
  1. public PublicKey geneneratePublicKey(byte[] key) throws InvalidKeySpecException, NoSuchAlgorithmException{
  2. KeySpec keySpec = new X509EncodedKeySpec(key);
  3. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  4. return keyFactory.generatePublic(keySpec);
  5. }
    public PublicKey geneneratePublicKey(byte[] key) throws InvalidKeySpecException, NoSuchAlgorithmException{
KeySpec keySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}

二、PEM编码

PEM编码也是密钥对较常用的编码方式,openssl则是以PEM编码为主,相对DER对人可读性更强,以BASE64编码呈现,外围包上类似-----BEGIN RSA PRIVATE KEY-----。

JCE没有对PEM直接支持的方式,但是可以通过第三方包例如bouncycastle解析,当然如果想要自己理解pem编码结构,也可以自己写代码解析。

这里介绍下如何使用bouncycastle进行解析。

[java] view plaincopyprint?
  1. FileInputStream fis = new FileInputStream("id_rsa");
  2. byte[] key = PrivateKeyUtils.readStreamToBytes(fis);
  3. Security.addProvider(new BouncyCastleProvider());
  4. ByteArrayInputStream bais = new ByteArrayInputStream(key);
  5. PEMReader reader = new PEMReader(new InputStreamReader(bais), new PasswordFinder() {
  6. @Override
  7. public char[] getPassword() {
  8. return "".toCharArray();
  9. }
  10. });
  11. KeyPair keyPair = (KeyPair) reader.readObject();
  12. reader.close();
  13. PublicKey pubk = keyPair.getPublic();
  14. System.out.println(pubk);
  15. PrivateKey prik = keyPair.getPrivate();
  16. System.out.println(prik);
  17. KeySpec keySpec = new X509EncodedKeySpec(pubk.getEncoded());
  18. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  19. System.out.println(keyFactory.generatePublic(keySpec));
  20. KeySpec keySpec2 = new PKCS8EncodedKeySpec(prik.getEncoded());
  21. System.out.println(keyFactory.generatePrivate(keySpec2));
      FileInputStream fis = new FileInputStream("id_rsa");
byte[] key = PrivateKeyUtils.readStreamToBytes(fis);
Security.addProvider(new BouncyCastleProvider());
ByteArrayInputStream bais = new ByteArrayInputStream(key);
PEMReader reader = new PEMReader(new InputStreamReader(bais), new PasswordFinder() {
@Override
public char[] getPassword() {
return "".toCharArray();
}
});
KeyPair keyPair = (KeyPair) reader.readObject();
reader.close();
PublicKey pubk = keyPair.getPublic();
System.out.println(pubk);
PrivateKey prik = keyPair.getPrivate();
System.out.println(prik);
KeySpec keySpec = new X509EncodedKeySpec(pubk.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
System.out.println(keyFactory.generatePublic(keySpec));
KeySpec keySpec2 = new PKCS8EncodedKeySpec(prik.getEncoded());
System.out.println(keyFactory.generatePrivate(keySpec2));

看下这个输出结果

[plain] view plaincopyprint?
  1. RSA Public Key
  2. modulus: c8f3e2d2e7fffe049127a115cab648fa9f55a7712d40868dccbddef9ebf030480a31f060e6c1ace2c53660e467cd173870367223dccea00ef2bdf6795757eb34fe1e8cfb63a0d333eefc9739029512df68108dd4b8054a12bdb206abd2ee7a727faa79604680c1337473ecd3d9a1a10b6cbc3af7862a74619ea7fe3a5bb2b89dded41dc5e4e4d5fcad169b85a599487929de1788e1e9a8d4efae4fda811d1e4d975b50d0d61b5887402ca975ec5e1d3ff193522b84746fe35ab00d073fed466786d9303f19c642c02cb1ad3a1ec6f0b7234e492e79500ee0bb1c1f07c23ae70af9b75aa35a6c75573d302cbf8f034341932dc371689b9f952388328c5277c117
  3. public exponent: 10001
  4. RSA Private CRT Key
  5. modulus: c8f3e2d2e7fffe049127a115cab648fa9f55a7712d40868dccbddef9ebf030480a31f060e6c1ace2c53660e467cd173870367223dccea00ef2bdf6795757eb34fe1e8cfb63a0d333eefc9739029512df68108dd4b8054a12bdb206abd2ee7a727faa79604680c1337473ecd3d9a1a10b6cbc3af7862a74619ea7fe3a5bb2b89dded41dc5e4e4d5fcad169b85a599487929de1788e1e9a8d4efae4fda811d1e4d975b50d0d61b5887402ca975ec5e1d3ff193522b84746fe35ab00d073fed466786d9303f19c642c02cb1ad3a1ec6f0b7234e492e79500ee0bb1c1f07c23ae70af9b75aa35a6c75573d302cbf8f034341932dc371689b9f952388328c5277c117
  6. public exponent: 10001
  7. xxx
  8. Sun RSA public key, 2048 bits
  9. modulus: 25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
  10. public exponent: 65537
  11. Sun RSA private CRT key, 2048 bits
  12. modulus:          25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
  13. public exponent:  65537
  14. xxx
RSA Public Key
modulus: c8f3e2d2e7fffe049127a115cab648fa9f55a7712d40868dccbddef9ebf030480a31f060e6c1ace2c53660e467cd173870367223dccea00ef2bdf6795757eb34fe1e8cfb63a0d333eefc9739029512df68108dd4b8054a12bdb206abd2ee7a727faa79604680c1337473ecd3d9a1a10b6cbc3af7862a74619ea7fe3a5bb2b89dded41dc5e4e4d5fcad169b85a599487929de1788e1e9a8d4efae4fda811d1e4d975b50d0d61b5887402ca975ec5e1d3ff193522b84746fe35ab00d073fed466786d9303f19c642c02cb1ad3a1ec6f0b7234e492e79500ee0bb1c1f07c23ae70af9b75aa35a6c75573d302cbf8f034341932dc371689b9f952388328c5277c117
public exponent: 10001
RSA Private CRT Key
modulus: c8f3e2d2e7fffe049127a115cab648fa9f55a7712d40868dccbddef9ebf030480a31f060e6c1ace2c53660e467cd173870367223dccea00ef2bdf6795757eb34fe1e8cfb63a0d333eefc9739029512df68108dd4b8054a12bdb206abd2ee7a727faa79604680c1337473ecd3d9a1a10b6cbc3af7862a74619ea7fe3a5bb2b89dded41dc5e4e4d5fcad169b85a599487929de1788e1e9a8d4efae4fda811d1e4d975b50d0d61b5887402ca975ec5e1d3ff193522b84746fe35ab00d073fed466786d9303f19c642c02cb1ad3a1ec6f0b7234e492e79500ee0bb1c1f07c23ae70af9b75aa35a6c75573d302cbf8f034341932dc371689b9f952388328c5277c117
public exponent: 10001
xxx
Sun RSA public key, 2048 bits
modulus: 25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
public exponent: 65537
Sun RSA private CRT key, 2048 bits
modulus:          25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
public exponent:  65537
xxx

中间内容太多,略去了一部分,看下重点的public exponent部分,发现不同,但其实是一个是10进制输出,一个是16进制输出,所以在这里提个醒,这里生成过程没有错的。

三、openssh公钥

很多SSH公钥习惯使用openssh格式的,下面介绍下openssh格式的公钥如何解析,目前好像是没有官方库或者第三方库提供支持的。

openssh公钥呈现形式如

[plain] view plaincopyprint?
  1. ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCW6qYq6m8gVOWLyTB1JGl1aLrJDOCIfErXWNUsNeUXg4UdAtSbkiA+Ta9Nx6oMR4w+OkPbxyivnzkZt1YpmDxrm1z99z81/VyVw+lue+3neRjTgfGMascG+46b7DpEKLXlfS2hwOA+4ooRIeR+LbQZVovy5SP6ZTngskiqcySYqQ== RSA-1024
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCW6qYq6m8gVOWLyTB1JGl1aLrJDOCIfErXWNUsNeUXg4UdAtSbkiA+Ta9Nx6oMR4w+OkPbxyivnzkZt1YpmDxrm1z99z81/VyVw+lue+3neRjTgfGMascG+46b7DpEKLXlfS2hwOA+4ooRIeR+LbQZVovy5SP6ZTngskiqcySYqQ== RSA-1024

以ssh-rsa打头,描述“RSA-1024”结尾的形式,中间是Base64编码。

这里过滤掉除了Base64外的其他部分,解码Base64得到公钥二进制内容。

这里二进制编码格式如下:

前11字节固定

0 0 0 7  's' 's' 'h' '-' ‘r' 's' 'a'

紧接着4个字节为一个int值,表示public exponent所占字节长度

可通过移位符及相加或者BigInteger方式实现转换。

[java] view plaincopyprint?
  1. public static int decodeUInt32(byte[] key, int start_index){
  2. byte[] test = Arrays.copyOfRange(key, start_index, start_index + 4);
  3. return new BigInteger(test).intValue();
  4. //      int int_24 = (key[start_index++] << 24) & 0xff;
  5. //      int int_16 = (key[start_index++] << 16) & 0xff;
  6. //      int int_8 = (key[start_index++] << 8) & 0xff;
  7. //      int int_0 = key[start_index++] & 0xff;
  8. //      return int_24 + int_16 + int_8 + int_0;
  9. }
  public static int decodeUInt32(byte[] key, int start_index){
byte[] test = Arrays.copyOfRange(key, start_index, start_index + 4);
return new BigInteger(test).intValue();
//      int int_24 = (key[start_index++] << 24) & 0xff;
//      int int_16 = (key[start_index++] << 16) & 0xff;
//      int int_8 = (key[start_index++] << 8) & 0xff;
//      int int_0 = key[start_index++] & 0xff;
//      return int_24 + int_16 + int_8 + int_0;
}

得到长度后,再从后一字节开始读取该长度字节作为public exponent的值,构造相应BigInteger。

再紧接着4个字节也是一个int值,表示modulus所占字节长度,同理转换得到长度。

再根据长度读取字节数组得到modulus值即可。

相应代码如下

[java] view plaincopyprint?
  1. public static RSAPublicKey decodePublicKey(byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException{
  2. byte[] sshrsa = new byte[] { 0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's',
  3. 'a' };
  4. int start_index = sshrsa.length;
  5. /* Decode the public exponent */
  6. int len = decodeUInt32(key, start_index);
  7. start_index += 4;
  8. byte[] pe_b = new byte[len];
  9. for(int i= 0 ; i < len; i++){
  10. pe_b[i] = key[start_index++];
  11. }
  12. BigInteger pe = new BigInteger(pe_b);
  13. /* Decode the modulus */
  14. len = decodeUInt32(key, start_index);
  15. start_index += 4;
  16. byte[] md_b = new byte[len];
  17. for(int i = 0 ; i < len; i++){
  18. md_b[i] = key[start_index++];
  19. }
  20. BigInteger md = new BigInteger(md_b);
  21. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  22. KeySpec ks = new RSAPublicKeySpec(md, pe);
  23. return (RSAPublicKey) keyFactory.generatePublic(ks);
  24. }
   public static RSAPublicKey decodePublicKey(byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException{
byte[] sshrsa = new byte[] { 0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's',
'a' };
int start_index = sshrsa.length;
/* Decode the public exponent */
int len = decodeUInt32(key, start_index);
start_index += 4;
byte[] pe_b = new byte[len];
for(int i= 0 ; i < len; i++){
pe_b[i] = key[start_index++];
}
BigInteger pe = new BigInteger(pe_b);
/* Decode the modulus */
len = decodeUInt32(key, start_index);
start_index += 4;
byte[] md_b = new byte[len];
for(int i = 0 ; i < len; i++){
md_b[i] = key[start_index++];
}
BigInteger md = new BigInteger(md_b);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new RSAPublicKeySpec(md, pe);
return (RSAPublicKey) keyFactory.generatePublic(ks);
}

四、其他编码

后续有机会再研究其他编码方式如何解析,不过可能bouncycastle已经提供了许多编码的解析,可以直接使用,具体没看,有兴趣的可以研究下。
下面有个网站介绍各种编码的,还有利用openssl进行各种转换的
http://myonlineusb.wordpress.com/2011/06/19/what-are-the-differences-between-pem-der-p7bpkcs7-pfxpkcs12-certificates/
更多 0

JAVA解析各种编码密钥对(DER、PEM、openssh公钥)相关推荐

  1. java der pem_JAVA解析各种编码密钥对(DER、PEM、openssh公钥)

    一.DER编码密钥对 先说下DER编码,是因为JCE本身是支持DER编码密钥对的解析的,可以参见PKCS8EncodedKeySpec和X509EncodedKeySpec. DER编码是ASN.1编 ...

  2. Java解析Base64编码为图片

    创建工具类 在转换前需要对base64编码进行处理,把头部信息去掉,根据不同的图片格式而不同 data:image/png;base64为png格式的图片.其他格式的base64编码需要进行相对应的改 ...

  3. java 解析der文件_java-如何读取也用bouncycastle在DER中编码的PK...

    我已经尝试过以下问题的答案: 但是由于我调用时我的加密密钥已编码为DER Object object = pemParser.readObject(); 对象为null. 我可以使用openssl的命 ...

  4. JAVA解析html文档,替换img图片路径成base64编码,并将文章存入数据库

    转载自  JAVA解析html文档,替换img图片路径成base64编码,并将文章存入数据库 开发环境:struts2+ spring + hibernate 数据库:oracle 需求:在HTML编 ...

  5. java中base64编码加密和android中base64编码加密不一样?base64编码解析错误?

    在android的base64加密后得到: WwogIHsKICAgICJ0MSI6ICIwIiwKICAgICJ0MiI6ICIyNDM4NCIsCiAgICAidDMiOiAiIiwKICAgIC ...

  6. 详解Java解析XML的四种方法

    http://developer.51cto.com  2009-03-31 13:12  cnlw1985  javaeye  我要评论(8) XML现在已经成为一种通用的数据交换格式,平台的无关性 ...

  7. Java解析XML汇总(DOM/SAX/JDOM/DOM4j/XPath)

    http://blog.csdn.net/smcwwh/article/details/7183869 关键字:Java解析xml.解析xml四种方法.DOM.SAX.JDOM.DOM4j.XPath ...

  8. java 解析/操作 xml 几种常用方式 xml的增加/删除/修改

    java 解析/操作 xml 几种常用方式 xml的增加/删除/修改 首先,我们先介绍几种常用的xml解析器. 1. 介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方 ...

  9. (best!)JAVA中文字符编码问题详解

    转载自:http://blog.csdn.net/youyue/article/details/4580402 JAVA中文字符编码问题详解 JAVA的中文字符乱码问题一直很让人头疼.特别是在WEB应 ...

最新文章

  1. leetcode算法题--子集
  2. Java并发编程(4):守护线程与线程阻塞的四种情况
  3. JVM学习笔记之-执行引擎(Execution Engine)
  4. mysql数据库version版本控制_MySQL数据库版本控制
  5. C# MVC 用户登录状态判断
  6. python数据预测模型算法_Python AI极简入门:4、使用回归模型预测房价
  7. 参数方法(parameter)与非参数方法(nonparameter)
  8. Slider 滑动条效果
  9. ACC 时间范围处理
  10. 为了健康,别做这20件事
  11. 美图秀秀计算机教程,如何用美图秀秀换背景?美图秀秀换背景图文教程-电脑教程...
  12. 《国际经济学(商学院)》
  13. 腾讯秀丽江山之长歌行服务器维护,37秀丽江山之长歌行服务器正式关服公告
  14. 知道Unicode表的数字,怎么用java推出相对应的日文?
  15. Vue 使用 yarn 报错
  16. SecureCRT工具介绍
  17. CSAPP: Architecture Lab
  18. YOLOv5-7.0解决No module named ‘utils.datasets‘和cannot import name ‘scale_coords‘ from ‘utils.general‘
  19. ug曲面建模实例教程计算机,UG曲面造型实例-直接建模
  20. java 流 改变编码_Java-IO流之转换流的使用和编码与解码原理

热门文章

  1. 算法--三种方法求连续子数组的最大和
  2. python费用结算系统_python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
  3. Python3 环境搭建、pycharm安装配置详解、新建Python项目(新手小白版Windows系统)
  4. 虚拟化技术原理与实现 pdf_多进程的实现原理-多道技术
  5. linux 查看sql进程id,根据进程的ID取得该进程的SQL脚本
  6. 简易linux修改ip,让Linux修改IP、DNS等可以更简单
  7. linux 跟踪程序执行过程,用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪
  8. file extension php,.php File Extension
  9. 修改服务器劫包,APP游戏TCP包被劫持篡改的一些解决方案
  10. nohup 不生成日志_js页面触发chargeRequest事件和Nginx获取日志信息