【问题标题】:Converting P1363 format to ASN.1/DER format using Java使用 Java 将 P1363 格式转换为 ASN.1/DER 格式
【发布时间】:2020-05-19 00:07:48
【问题描述】:

背景

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

由于我是客户端,我无法更改服务器代码。服务器正在使用SHA386withECDSA

我需要什么

1) 谁能给我提供准确的代码 sn-p 以在 Java 中将其从 P1363 格式转换为 ASN.1,反之亦然(ASN.1 到 P1363)。我尝试了一些代码 sn-ps 但无法使其工作(因为那些 sn-ps 是 C、C++ 中的)。

2) 是否有一个库可以用来进行这些转换而无需自己编写。像充气城堡一样提供这个吗?

我知道的

我也知道我可以将 BouncyCastle 与 SHAXwithPLAIN-ECDSASHAXwithCVC-ECDSA 一起使用。然而,Bouncy Castle/ Spongy Castle 在 Android 上运行时会很慢,因为它不进行本地调用。 Java 9 也提供该支持,但我仍在使用 Java 8。

【问题讨论】:

  • 众所周知,MSRCrypto 以 P1363 格式发送它... P1363 是公钥加密原语的大标准。我从未听说过“P1363”格式,但如果该标准中描述了多种格式,我不会感到惊讶。在任何有用的意义上,ASN.1 或 DER 都不是真正的格式。 ASN.1 是用于描述许多不同格式的语言,DER 是一种将 ASN.1 结构编码和解码到/从字节的方法。与大多数 stackoverflow 问题一样,这个问题可能需要其中的代码才能被理解。
  • @PresidentJamesK.Polk:ECDSA 签名的广泛使用(而且非常简单)的 ASN.1 语法在 SEC1 中,来自 SECG、rfc3279、rfc5480,显然是最近/当前的 X9.62,但我没有没花钱。
  • @dave_thompson_085:只是两个整数的序列,对吧?
  • @PresidentJamesK.Polk:是的

标签: java cryptography sign ecdsa


【解决方案1】:

BouncyCastle 没有将一种签名格式直接转换为另一种的功能。它确实有一个通用的 ASN.1 编码/解码库(对于 DER 和 BER,尽管加密几乎完全使用 DER)可以处理 ASN.1 的一半,但你仍然需要做'plain'(P1363, CVC,PKCS11,Microsoft)一半,在输入(解码)端非常容易,但在输出(编码)端有点难。对于该格式,您需要知道并使用曲线顺序的八位字节大小(或者更准确地说是生成器和子组顺序,有时与基础曲线不同),我在这里称之为 n。

我展示了非常有限的错误处理,包括抛出一个无意义的异常并让 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();
}

【讨论】:

  • 嘿 @dave_thompson_085 上面的转换器从 ASN1 转换为固定格式。是否有任何代码 sn-p 可以从固定格式转换为 ASN1,因为我的服务器将其作为固定格式发送。
  • 使用的曲线是secp384r1
  • Aditya:Convert1 普通到 DER,Convert2 是 DER 到普通。 secp384r1(又名 P-384)具有 384 位顺序,因此使用 384/8,即 n 为 48。
猜你喜欢
  • 2020-01-25
  • 2011-07-20
  • 1970-01-01
  • 2011-08-23
  • 2012-06-20
  • 1970-01-01
  • 2020-01-28
  • 2022-07-01
  • 1970-01-01
相关资源
最近更新 更多