当前位置: 首页 > 工具软件 > mod_asn > 使用案例 >

java算法中使用的ASN编码格式

翟嘉祥
2023-12-01

前言

java中的算法实现,不论是生成密钥、生成签名都会对结果进行编码,而编码方式则是ASN.1格式

java.security.Key

这个接口是java中算法密钥接口,定义了所有算法密钥的最顶层设计。

其中getFormat()接口返回这个密钥的编码方式。

getEncoded()接口返回编码后的密钥值。

其中密钥的编码格式是什么?其注释中也有相关说明

/**
* <LI>An Encoded Form
*
* <P>This is an external encoded form for the key used when a standard
* representation of the key is needed outside the Java Virtual Machine,
* as when transmitting the key to some other party. The key
* is encoded according to a standard format (such as
* X.509 {@code SubjectPublicKeyInfo} or PKCS#8), and
* is returned using the {@link #getEncoded() getEncoded} method.
* Note: The syntax of the ASN.1 type {@code SubjectPublicKeyInfo}
* is defined as follows:
*
* <pre>
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
* </pre>
*
* For more information, see
* <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
* Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a>.
*
* <LI>A Format
*
* <P>This is the name of the format of the encoded key. It is returned
* by the {@link #getFormat() getFormat} method.
*
* </UL>
**/

由上面注释可知,其中publicKey的格式是按照ASN.1格式去编码,并且有SubjectPublicKeyInfo结构体来承载publicKey的信息。

java rsa算法解析编码后的公私玥

public static void main(String[] args) throws Exception{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

/**
* 解析编码后的publicKey
*/
PublicKey publicKey = keyPair.getPublic();

byte[] b = publicKey.getEncoded();
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(b);
AlgorithmIdentifier algorithmIdentifier = publicKeyInfo.getAlgorithm();
DERBitString derBitString = publicKeyInfo.getPublicKeyData();
byte[] bit = derBitString.getBytes();
System.out.println(HexUtil.byteToHex(bit));

ASN1Sequence seq = ASN1Sequence.getInstance(bit);
byte[] exponent = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().toByteArray();
byte[] modulus = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().toByteArray();

System.out.println(HexUtil.byteToHex(exponent));
System.out.println(HexUtil.byteToHex(modulus));


/**
* 解析编码后的privateKey
*/
PrivateKey privateKey = keyPair.getPrivate();
byte[] bb = privateKey.getEncoded();

ASN1Sequence seq1 = ASN1Sequence.getInstance(bb);
ASN1OctetString derOctetString = ASN1OctetString.getInstance(seq1.getObjectAt(2));
byte[] bbb = derOctetString.getOctets();

ASN1Sequence seq11 = ASN1Sequence.getInstance(bbb);
byte[] pri_exponent = ASN1Integer.getInstance(seq11.getObjectAt(1)).getValue().toByteArray();
byte[] pri_modulus = ASN1Integer.getInstance(seq11.getObjectAt(3)).getValue().toByteArray();

System.out.println(HexUtil.byteToHex(pri_exponent));
System.out.println(HexUtil.byteToHex(pri_modulus));

}

java ecc算法解析编码后的签名值

import com.sankuai.cx.etcp.code.util.HexUtil;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;

/**
* @Author:wangchao
* @Date: 2019/8/8 11:17 AM
* @Description:
**/
public class ASNUtil {

/**
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
* @param sign in plain byte array
* @return rs result in asn1 format
*/
public static byte[] rsPlainByteArrayToAsn1(byte[] sign,int rsLen){
if(sign.length != rsLen * 2) {
throw new RuntimeException("err rs. ");
}
BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, rsLen));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, rsLen, rsLen * 2));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r));
v.add(new ASN1Integer(s));
try {
return new DERSequence(v).getEncoded("DER");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
* @param rsDer rs in asn1 format
* @return sign result in plain byte array
*/
public static byte[] rsAsn1ToPlainByteArray(byte[] rsDer,int rsLen){
ASN1Sequence seq = ASN1Sequence.getInstance(rsDer);
byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(),rsLen);
byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue(),rsLen);
byte[] result = new byte[rsLen * 2];
System.arraycopy(r, 0, result, 0, r.length);
System.arraycopy(s, 0, result, rsLen, s.length);
return result;
}

public static byte[] bigIntToFixexLengthBytes(BigInteger rOrS,int FixedLength){
// for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
// r and s are the result of mod n, so they should be less than n and have length<=32
byte[] rs = rOrS.toByteArray();
if(rs.length == FixedLength) {
return rs;
}
else if(rs.length == FixedLength + 1 && rs[0] == 0){
return Arrays.copyOfRange(rs, 1, FixedLength + 1);
}
else if(rs.length < FixedLength) {
byte[] result = new byte[FixedLength];
Arrays.fill(result, (byte)0);
System.arraycopy(rs, 0, result, FixedLength - rs.length, rs.length);
return result;
} else {
throw new RuntimeException("err rs: " + HexUtil.byteToHex(rs));
}
}
}

注意:上面两段代码示例,均依赖 bouncycastle的实现

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15on</artifactId>
<version>1.59</version>
</dependency>

 类似资料: