Converting P1363 format to ASN.1/DER format using Java

此生再无相见时 提交于 2020-06-17 09:45:07

问题


BackGround

I have a server which uses MSRCrypto to sign my nonce. I need to verify that nonce in Java. It is well know that MSRCrypto sends it in P1363 format and Java Library requires it in DER format.

I cannot change the server code as I am the client. The server is using SHA386withECDSA

What I need

1) Can someone provide me with exact code snippet to convert it from P1363 format to ASN.1 and vice-versa(ASN.1 to P1363) in Java. I tried a few code snippets but was not able to make it work (because those snippets were in C, C++).

2) Is there a library which I can use to do these conversion without writing it myself. Like does Bouncy Castle provide this?

What I am aware of

I am also aware that I can use BouncyCastle with SHAXwithPLAIN-ECDSA or with SHAXwithCVC-ECDSA. However Bouncy Castle/ Spongy Castle is slow when running this on Android because it does not do native calls. The support is also available in Java 9 but I am still using Java 8.


回答1:


BouncyCastle doesn't have a facility to directly convert one signature format to the other. It does have a general-purpose ASN.1 encoding/decoding library (for both DER and BER, although crypto uses almost entirely DER) which can handle the ASN.1 half, but you still have to do the 'plain' (P1363, CVC, PKCS11, Microsoft) half, which is dead easy on the input (decode) side but a little harder on the output (encode) side. For that format you need to know and use the size in octets of the curve order (or more exactly the generator and subgroup order, which sometimes differs from the underlying curve), which I call n here.

I show very limited error handling, consisting of throwing an uninformative Exception and letting the JVM display it. In a real program you will want to do better, but what you will want to do varies.

static void SO61860104Convert1 (String[] args) throws Exception {
    int n = 32; // for example assume 256-bit-order curve like P-256
    byte[] plain = Files.readAllBytes(Paths.get(args[0]));

    // common
    BigInteger r = new BigInteger (+1, Arrays.copyOfRange(plain,0,n));
    BigInteger s = new BigInteger (+1, Arrays.copyOfRange(plain,n,n*2));

    // with BouncyCastle
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new ASN1Integer(r)); v.add(new ASN1Integer(s));
    Files.write(Paths.get(args[1]), new DERSequence(v) .getEncoded() );

    // without
    byte[] x1 = r.toByteArray(), x2 = s.toByteArray(); 
    // already trimmed two's complement, as DER wants
    int len = x1.length + x2.length + (2+2), idx = len>=128? 3: 2;
    // the len>=128 case can only occur for curves of 488 bits or more,
    // and can be removed if you will definitely not use such curve(s)
    byte[] out = new byte[idx+len]; out[0] = 0x30; 
    if( idx==3 ){ out[1] = (byte)0x81; out[2] = (byte)len; } else { out[1] = (byte)len; }
    out[idx] = 2; out[idx+1] = (byte)x1.length; System.arraycopy(x1, 0, out, idx+2, x1.length);
    idx += x1.length + 2;
    out[idx] = 2; out[idx+1] = (byte)x2.length; System.arraycopy(x2, 0, out, idx+2, x2.length);
    Files.write(Paths.get(args[2]), out);
}
static void SO61860104Convert2 (String[] args) throws Exception {
    int n = 32; // for example assume 256-bit-order curve like P-256
    byte[] der = Files.readAllBytes(Paths.get(args[0]));
    BigInteger r, s;
    byte[] out;

    // with BouncyCastle
    ASN1Sequence seq = ASN1Sequence.getInstance(der);
    r = ((ASN1Integer)seq.getObjectAt(0)).getValue();
    s = ((ASN1Integer)seq.getObjectAt(1)).getValue();
    // common output
    out = new byte[2*n]; toFixed(r, out, 0, n); toFixed(s, out, n, n);
    Files.write(Paths.get(args[1]), out);

    // without
    if( der[0] != 0x30 ) throw new Exception();
    int idx = der[1]==0x81? 3: 2; // the 0x81 case only occurs for curve over 488 bits
    if( der[idx] != 2 ) throw new Exception();
    r = new BigInteger (1, Arrays.copyOfRange(der,  idx+2, idx+2+der[idx+1]));
    idx += der[idx+1] + 2;
    if( der[idx] != 2 ) throw new Exception();
    s = new BigInteger (1, Arrays.copyOfRange(der,  idx+2, idx+2+der[idx+1]));
    if( idx + der[idx+1] + 2 != der.length ) throw new Exception();
    // common output
    out = new byte[2*n]; toFixed(r, out, 0, n); toFixed(s, out, n, n);
    Files.write(Paths.get(args[2]), out);
}
static void toFixed (BigInteger x, byte[] a, int off, int len) throws Exception {
    byte[] t = x.toByteArray();
    if( t.length == len+1 && t[0] == 0 ) System.arraycopy (t,1, a,off, len);
    else if( t.length <= len ) System.arraycopy (t,0, a,off+len-t.length, t.length);
    else throw new Exception();
}


来源:https://stackoverflow.com/questions/61860104/converting-p1363-format-to-asn-1-der-format-using-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!