JAVA解析各种编码密钥对(DER、PEM、openssh公钥)
一、DER编码密钥对
先说下DER编码,是因为JCE本身是支持DER编码密钥对的解析的,可以参见PKCS8EncodedKeySpec和X509EncodedKeySpec.
DER编码是ASN.1编码规则中的一个子集,具体格式如何编排没有去了解,但最终呈现肯定的是一堆有规律的二进制组合而成。
PKCS#8定义了私钥信息语法和加密私钥语法,而X509定义证书规范,通常都会用DER和PEM进行编码存储,而在JAVA中则使用的
DER。
接下来看看如果通过DER编码的密钥对分别获取JAVA的公私钥对象。
1.下面一段是生成私钥对象的,传入参数是DER编码的私钥内容。
- @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编码公钥内容,可以看到和生成私钥的部分非常相似。
- 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进行解析。
- 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));
看下这个输出结果
- 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公钥呈现形式如
- 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方式实现转换。
- 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值即可。
相应代码如下
- 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);
- }
四、其他编码
JAVA解析各种编码密钥对(DER、PEM、openssh公钥)的更多相关文章
- JAVA解析XML的四种方式
java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这 ...
- 【Java】详解Java解析XML的四种方法
XML现在已经成为一种通用的数据交换格式,平台的无关性使得很多场合都需要用到XML.本文将详细介绍用Java解析XML的四种方法. AD: XML现在已经成为一种通用的数据交换格式,它的平台无关性,语 ...
- java解析xml的几种方式
java解析xml的几种方式 DOM DOM的全称是Document ObjectModel,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称D ...
- Java解析XML之Dom4j
Java解析XML文件的方法有多种,个人感觉最常用的是使用Dom4j来解析XML文件.下面就简单介绍下Dom4j的基础使用. Dom4j需要jar包的支持,大家可以从网络上下载,如dom4j-1.6. ...
- 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来 ...
- 使用Java解析XML文件或XML字符串的例子
转: 使用Java解析XML文件或XML字符串的例子 2017年09月16日 11:36:18 inter_peng 阅读数:4561 标签: JavaXML-Parserdom4j 更多 个人分类: ...
- AJPFX解析关于编码ansi、GB2312、unicode与utf-8的区别
大家平时遇到乱码问题是否有自己的一套解决方案?这篇文章就是介绍一下常用的编码方式关于编码ansi.GB2312.unicode与utf-8的区别 先做一个小小的试验: 在一个文件夹里,把一个txt文本 ...
- XML基础+Java解析XML +几种解析方式的性能比较
XML基础+Java解析XML 一:XML基础 XML是什么: 可扩展的标记语言 XML能干什么: 描述数据.存储数据.传输(交换)数据. XML与HTML区别: 目的不一样 XML 被设计用来描述数 ...
- java解析xml的三种方法
java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...
随机推荐
- dedecms 列表每隔6行输出一个空li
{dede:list pagesize='33'} <li class="hang"><a href="[field:arcurl/]" ta ...
- FreeBSD基金会添加新成员,梁莉成为第一位来自微软和中国的基金会董事
这个月23日FreeBSD基金会很高兴地宣布Philip Paeps和Kylie Liang (梁莉)正式加入董事会. 梁莉,现任微软开源技术部高级项目经理,主要负责FreeBSD在公有云以及私有云的 ...
- 1分钟学会Markdown语法
markdown 简明语法 基本符号 *,-,+ 3个符号效果都一样,这3个符号被称为 Markdown符号 空白行表示另起一个段落 `是表示inline代码,tab是用来标记 代码段,分别对应htm ...
- 使用Jmeter测试MySQL性能——(2)多客户端配置
在测试性能过程中,单个测试客户端可能存在性能瓶颈无法达到测试要求的压力.在这种情况下,可以设置jmeter的多客户端模式,然后通过一台控制端,同时控制多台PC上的客户端向服务器发送测试请求.若有4台P ...
- 自动构建Makefile(1)--C/C++编译流程&Makefile规则简介
前言: 大家在Windows上使用VS构建C/C++程序时,不需要自己编辑略显晦涩的Makefile文件,而对于初学者而言, 他们甚至没意识到它的存在.VS是自动生成Makefile文件, 并构建 ...
- 递归神经网络之理解长短期记忆网络(LSTM NetWorks)(转载)
递归神经网络 人类并不是每时每刻都从头开始思考.正如你阅读这篇文章的时候,你是在理解前面词语的基础上来理解每个词.你不会丢弃所有已知的信息而从头开始思考.你的思想具有持续性. 传统的神经网络不能做到这 ...
- 2015GitWebRTC编译实录7
2015.07.20 libvoiceengine 编译通过去除了mock测试代码,mock是用来进行测试的,意义不大.另外会报一个常量错误,需要定义WEBRTC_MAC宏,只定义WEBRTC_IOS ...
- ZOJ 1201 Inversion
原题链接 题目大意:给一个数组{ A1,A2,…,An } ,要求生成另一个数组B1,B2,…,Bn,使得Bi表示的是在数组A中排在i前面大于i的数字的个数.题目的输入是数组A(字母P表示)或者数组B ...
- HTMO DOM部分---小练习;列表之间移动、日期选择、好友选中、滑动效果、滚动条效果、飞入飞出效果。
一:列表之间数据移动 第一个列表里面有内容,第二个里面没有 实现功能: 点击左侧列表选中一项内容,点击按钮,复制到右侧 点击复制所有按钮,将左侧列表所有数据,复制到右侧 扩展功能:右侧列表实现去重复 ...
- 关于xmlhttprequest的readystate属性的五个状态
http://www.cnblogs.com/jerry01/archive/2009/09/03/1559624.html 昨天做了一个利用 ajax实现页面无刷新的从服务器端获得时间的例子,当时对 ...