添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

一、DER编码密钥对

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

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

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

接下来看看如果通过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
Sun RSA public key, 2048 bits
  modulus: 25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
  public exponent: 65537
Sun RSA private CRT key, 2048 bits
  modulus:          25367925677263221630752072905429434117596189021449325931333193529363239091429133073657699480437320802724298965580526553453499379398405915207286949216370963889754756788008021698178495726807109888833039800230667805051637457878962812581009778614579379073430749907762728841603230968432191178635884450213875555645164935313884823663096624318071901833679005494934145072511042211644746801428698070096755012497436134537077746175344235590315572214836519284172251946833712681076781034466422251569387242330311670205489884189790153154281087401570994337126054046621401176808489895271448688335849540690562754961439975230588159770903
  public exponent:  65537
中间内容太多,略去了一部分,看下重点的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);

四、其他编码

后续有机会再研究其他编码方式如何解析,不过可能bouncycastle已经提供了许多编码的解析,可以直接使用,具体没看,有兴趣的可以研究下。 一、DER编码密钥对先说下DER编码,是因为JCE本身是支持DER编码密钥对的解析的,可以参见PKCS8EncodedKeySpec和X509EncodedKeySpec.DER编码是ASN.1编码规则中的一个子集,具体格式如何编排没有去了解,但最终呈现肯定的是一堆有规律的二进制组合而成。PKCS#8定义了私钥信息语法和加密私钥语法,而X509定义证书规范,通常都会用DER和PEM
使用ssh-keygen生成的秘钥发现变成了如下格式: -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAA... -----END OPENSSH PRIVATE KEY----- 这是一种新的密钥格式, 而且很多软件对这种格式的密钥都是不支持的。比如我常用的git图形化操作软件gitkraken...
长度小于等于127,必须使用短型长度表示法。 长度大于127,必须使用长型长度表示法,并且要尽可能的短。 对于简单的string类型以及在其基础上隐性标签生成的类型使用简单定长表示法。 对于结构化类型以及在其基础上隐性标签生成的类型以
DER(Distinguished Encoding Rules,可辨别编码规则) DER 广泛用于X.509等数字证书。PEM文件 是Base64编码DER证书 ASN.1编码格式: 基本编码规则(BER) 规范编码规则(CER) 可分辨编码规则(DER) BER 编码 基本编码规则的格式指定了用于编码 ASN.1 数据结构的自描述和自定界格式。每个数据元素都被编码为类型标识符、长度描述、实际数据元素以及必要时的内容结束标记。这些类型的编码通常称为类型-长度-值(TLV) 编码。这种格式允许接收.
RSAPrivateKey::=SEQUENCE{ versionVersion, -- 当前的RSA版本,一般是 0x00 modulusINTEGER, --n 是 RSA合数模 n publicExponentINTEGER, --e 是 RSA的公开...
Python学习随笔(一) Python是解释性语言,python解释器一般为CPython(C语言开发) python注释符为#,转义字符 \,采用缩进方式(4个空格),大小写敏感 解释性语言是使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行,执行效率低,不能脱离解释器运行,跨平台性容易,只需提供特定解释器,如Python,JavaScript 编译型语言是使用专门的编译器将源代码一次性编译成可被该平台硬件执行的机器码,编译好的可执行性文件(.exe),可在相对应的平台上直接运行,移植性
最近在搞udp可靠通信(不单单是丢失重传),为了进行密钥传输学习一下密钥长度的一些知识,mark一下 java默认的rsa填充方案为RSA/ECB/PKCS1Padding 一般说的rsa密钥长度单位是bit,本文所有长度单位均为byte,除非另有说明 java的实现中 设:密钥模数长度(与密钥长度相等)lm,公钥e长度lpube,私钥e长度lprie 一、密钥长度=lm 二、lpu...
要读取SM2的PEM文件中的公钥,可以使用Bouncy Castle库。以下是使用Bouncy Castle库读取SM2 PEM文件中的公钥Java代码示例: ```java import java.io.FileReader; import java.security.KeyFactory; import java.security.Security; import java.security.interfaces.ECPublicKey; import java.security.spec.X509EncodedKeySpec; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; public class SM2PublicKeyReader { public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); // 读取PEM文件 FileReader fileReader = new FileReader("sm2.pem"); PEMParser pemParser = new PEMParser(fileReader); // 解析PublicKey JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); Object object = pemParser.readObject(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(converter.getPublicKey((BCECPublicKey) object).getEncoded()); ECPublicKey publicKey = (ECPublicKey) KeyFactory.getInstance("EC", "BC").generatePublic(keySpec); // 获取公钥参数 X9ECParameters ecParams = ((BCECPublicKey) publicKey).getParameters(); // 使用公钥进行加解密等操作 // ... pemParser.close(); 注意,这里的`sm2.pem`文件只包含公钥解析出来的公钥类型为`ECPublicKey`。您还可以使用`getParams()`方法获取公钥的参数。在此示例中,我们使用`X9ECParameters`类型来获取公钥的参数。 如果您想要读取PEM文件中的私钥,请参考我之前的回答。
python-memcached并发调用get/set时出现RunTimeError:Second simultaneous read on fileno 8 detected. Jeff Dauglas: https://groups.google.com/g/gevent/c/ULKUPvbaQ7I python-memcached并发调用get/set时出现RunTimeError:Second simultaneous read on fileno 8 detected. Jeff Dauglas: [code=python] import gevent.monkey gevent.monkey.patch_all() import corolocal import threading threading.local = corolocal.local [/code] python-memcached并发调用get/set时出现RunTimeError:Second simultaneous read on fileno 8 detected. Jeff Dauglas: 可以看看这个。 https://groups.google.com/g/gevent/c/ULKUPvbaQ7I import gevent.monkey gevent.monkey.patch_all() import corolocal import threading threading.local = corolocal.local [code=python] [/code] openssl签名验证、信封加密解密、产生随机数、md5摘要 ret=EVP_OpenInit(&ctx2,EVP_des_ede3_cbc(),ek[0],ekl[0],iv,pubkey[0]); //设置公钥 |||应该是设置私钥