导出ASN.1格式,然后使用Base64 JAVA进行编码

时间:2017-06-12 14:28:48

标签: java encoding bouncycastle asn.1

我想制作一个自定义ASN.1结构,包括3个PrintableString&1和OctetString。我正在使用BouncyCastle框架来处理这个问题。

所以我在我的类中设置了所需的参数,现在我必须以ASN.1格式返回此结构,然后使用Base64(其参数为byte [])对其进行编码,然后进入PEM格式。

所以我的问题是,我必须从方法getASN1format()返回什么类型的对象?

我的代码:

import org.bouncycastle.asn1.*;
import java.io.IOException;

public class ASN1Handshake1 implements ASN1Encodable {
    private DERPrintableString A, B, ID_PASS;
    private ASN1OctetString ID_K;

    public ASN1Handshake1(String A, String B, String ID_K, String ID_PASS, TTP TTPs ) throws IOException {
        this.A = new DERPrintableString(A);
        this.B = new DERPrintableString(B);
        this.ID_K = new DEROctetString(ID_K.getBytes());
        this.ID_PASS = new DERPrintableString(ID_PASS);
    }

    public ?? getASN1format(){
        //TODO
    }

    @Override
    public ASN1Primitive toASN1Primitive() {
        return null;
    }
}

1 个答案:

答案 0 :(得分:2)

I'm using Bouncy Castle 1.57 (bcprov-jdk15on) for this code.

First of all, keep in mind that ASN.1 is not a format per se, it's a description language that defines a structure, and PEM is a format that uses base 64. Many cryptography standards use ASN.1 to define their data structures, and PEM or DER (Distinguished Encoding Rules) to serialize those structures.

So, if you want to get the ASN.1 structure and format it to base64, you can do as below. You don't need a getASN1format method, just use the existent ones.

The fields can't just be "loose" in the ASN.1 structure. So I decided to put them in a sequence (using org.bouncycastle.asn1.DERSequence class), which is the best choice to store fields of a structure. I put them in the order they're declared, but of course you can choose any order you want.

I've also changed the variables names to follow Java's code conventions (names start with lowercase letters). So the class code is:

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;

public class ASN1Handshake1 extends ASN1Object {

    private DERPrintableString a, b, idPass;

    private ASN1OctetString idK;

    // removed TTPs parameter (it wasn't using it)
    public ASN1Handshake1(String a, String b, String idK, String idPass) {
        this.a = new DERPrintableString(a);
        this.b = new DERPrintableString(b);
        this.idK = new DEROctetString(idK.getBytes());
        this.idPass = new DERPrintableString(idPass);
    }

    // returns a DERSequence containing all the fields
    @Override
    public ASN1Primitive toASN1Primitive() {
        ASN1Encodable[] v = new ASN1Encodable[] { this.a, this.b, this.idK, this.idPass };
        return new DERSequence(v);
    }
}

To create a handshake object and convert it to base64 (the code below is not handling exceptions, so add the try/catch block accordingly):

import org.bouncycastle.util.encoders.Base64;

// create handshake object with some sample data
ASN1Handshake1 handshake = new ASN1Handshake1("a", "b", "ID_K", "ID_PASS");

// convert it to base64
String base64String = new String(Base64.encode(handshake.getEncoded()));
System.out.println(base64String);

This will output the handshake structure in base64 format:

MBUTAWETAWIEBElEX0sTB0lEX1BBU1M=

Please note that this is not a complete PEM (with headers like -----BEGIN CERTIFICATE-----) because your custom structure is not a predefined standard. So, you'll have to stay with this base64 generic string.

To check that the base64 string contains the ASN.1 sequence, just do:

// read from base64 String
ASN1Sequence seq = (ASN1Sequence) DERSequence.fromByteArray(Base64.decode(base64String.getBytes()));
int n = seq.size();
for (int i = 0; i < n; i++) {
    ASN1Encodable obj = seq.getObjectAt(i);
    if (obj instanceof DEROctetString) {
        System.out.println(new String(((DEROctetString) obj).getOctets()));
    } else {
        System.out.println(obj);
    }
}

The output is:

a
b
ID_K
ID_PASS