一、DER编码密钥对

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

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

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

DER。

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

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

  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. }

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

  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. }

二、PEM编码

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

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

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

  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));

看下这个输出结果

  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

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

三、openssh公钥

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

openssh公钥呈现形式如

  1. 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方式实现转换。

  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 exponent的值,构造相应BigInteger。

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

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

相应代码如下

  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. }

四、其他编码

后续有机会再研究其他编码方式如何解析,不过可能bouncycastle已经提供了许多编码的解析,可以直接使用,具体没看,有兴趣的可以研究下。
 
下面有个网站介绍各种编码的,还有利用openssl进行各种转换的

JAVA解析各种编码密钥对(DER、PEM、openssh公钥)的更多相关文章

  1. JAVA解析XML的四种方式

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这 ...

  2. 【Java】详解Java解析XML的四种方法

    XML现在已经成为一种通用的数据交换格式,平台的无关性使得很多场合都需要用到XML.本文将详细介绍用Java解析XML的四种方法. AD: XML现在已经成为一种通用的数据交换格式,它的平台无关性,语 ...

  3. java解析xml的几种方式

    java解析xml的几种方式 DOM DOM的全称是Document ObjectModel,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称D ...

  4. Java解析XML之Dom4j

    Java解析XML文件的方法有多种,个人感觉最常用的是使用Dom4j来解析XML文件.下面就简单介绍下Dom4j的基础使用. Dom4j需要jar包的支持,大家可以从网络上下载,如dom4j-1.6. ...

  5. XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax

    本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...

  6. 使用Java解析XML文件或XML字符串的例子

    转: 使用Java解析XML文件或XML字符串的例子 2017年09月16日 11:36:18 inter_peng 阅读数:4561 标签: JavaXML-Parserdom4j 更多 个人分类: ...

  7. AJPFX解析关于编码ansi、GB2312、unicode与utf-8的区别

    大家平时遇到乱码问题是否有自己的一套解决方案?这篇文章就是介绍一下常用的编码方式关于编码ansi.GB2312.unicode与utf-8的区别 先做一个小小的试验: 在一个文件夹里,把一个txt文本 ...

  8. XML基础+Java解析XML +几种解析方式的性能比较

    XML基础+Java解析XML 一:XML基础 XML是什么: 可扩展的标记语言 XML能干什么: 描述数据.存储数据.传输(交换)数据. XML与HTML区别: 目的不一样 XML 被设计用来描述数 ...

  9. java解析xml的三种方法

    java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...

随机推荐

  1. dbd到mongo的序列化问题及稳定性

    最近工作压力有点大,情绪偶然会失控,要好好反省一下自己. 上周本来打算写CSP相关的东西,但是目前做得还不够多,积累的经验不足,就放弃了.中间找到很好的参考资料,一并放在这里.一篇是比较短的论文,可以 ...

  2. div+css总结—FF下div不设置高度背景颜色或外边框不能正常显示的解决方法(借鉴)

    原地址:http://blog.sina.com.cn/s/blog_60b35e830100qwr2.html 在使用div+css进行网页布局时,如果外部div有背景颜色或者边框,而不设置其高度, ...

  3. OpenHCI - Open Host Controller Operational Registers

    The Host Controller (HC) contains a set of on-chip operational registers which are mapped into a non ...

  4. Core Java Volume I — 4.1. Introduction to Object-Oriented Programming

    4.1. Introduction to Object-Oriented ProgrammingObject-oriented programming, or OOP for short, is th ...

  5. 使用 CUBLAS 库给矩阵运算提速

    前言 编写 CUDA 程序真心不是个简单的事儿,调试也不方便,很费时.那么有没有一些现成的 CUDA 库来调用呢? 答案是有的,如 CUBLAS 就是 CUDA 专门用来解决线性代数运算的库. 本文将 ...

  6. DISCOVAR de novo

    海宝建议用这个拼接软件 http://www.broadinstitute.org/software/discovar/blog/?page_id=98 DISCOVAR – variant call ...

  7. Java-->List&Set

    一.List集合 特点:有序可重复 List集合的猜想: 1.每个元素是不是应该有序号 index 2.addFirst.addLast.set(intdex, 对象) 3.get(index)... ...

  8. 实战网卡bond

    一.什么是网卡bond 所谓bond,就是把多个物理网卡绑定成一个逻辑上的网卡,使用同一个IP工作,在增加带宽的同时也可以提高冗余性,一般使用较多的就是来提高冗余,分别和不同交换机相连,提高可靠性,但 ...

  9. ZMMR104-预留单批量删除及恢复

    ************************************************************************ Title : ZMMR104 ** Applicat ...

  10. Android EditText内容监听

    监听 EditText的内容变化,作出对应的处理. MainActivity.class package com.example.edittextdemo; import android.app.Ac ...