使用Java将P1363格式转换为ASN.1DER格式。

问题描述 投票:0回答:1

背景

我有一个服务器,它使用MSRCrypto来签署我的nonce。我需要在Java中验证该nonce。众所周知,MSRCrypto是以P1363格式发送的,而Java库要求以DER格式发送。

我不能改变服务器的代码,因为我是客户端。服务器使用的是 SHA386withECDSA

我需要什么

1) 谁能给我提供准确的代码片段,将P1363格式转换为ASN.1,反之亦然(ASN.1转换为P1363)。爪哇. 我尝试了一些代码片段,但无法使其工作(因为这些片段是在C,C++中)。

2) 有没有一个库可以让我不用自己写就能完成这些转换。比如Bouncy Castle是否提供这个功能?

我所知道的

我也知道,我可以使用BouncyCastle和 SHAXwithPLAIN-ECDSA 或与 SHAXwithCVC-ECDSA. 然而Bouncy Castle Spongy Castle在Android上运行时速度很慢,因为它不做本地调用。该支持在Java 9中也可以使用,但我仍然使用Java 8.BackGround 我有一个服务器,它使用MSRCrypto来签署我的nonce。

java cryptography sign ecdsa
1个回答
1
投票

BouncyCastle没有直接将一种签名格式转换为其他格式的功能。它有一个通用的 ASN.1 编码解码库(适用于 DER 和 BER,尽管加密技术几乎完全使用 DER),它可以处理 ASN.1 的一半,但你仍然必须处理 "普通"(P1363、CVC、PKCS11、Microsoft)的一半,这在输入(解码)端很容易,但在输出(编码)端有点困难。对于这种格式,你需要知道并使用曲线顺序(或者更准确的说是生成器和子组顺序,有时与底层曲线不同)的八位数大小,我在这里称之为n。

我展示了非常有限的错误处理,包括抛出一个无信息的Exception并让JVM显示它。在真实的程序中,你会希望做得更好,但是...。什么 你会想做的事情各不相同。

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();
}
© www.soinside.com 2019 - 2024. All rights reserved.