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



BackGround

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

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

我需要什么

1(有人可以向我提供确切的代码片段,以便在Java中将其从P1363格式转换为ASN.1,反之亦然(ASN.1到P1363(。我尝试了一些代码片段,但无法使其工作(因为这些片段在 C 中,C++(。

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

我所知道的

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

BouncyCastle没有直接将一种签名格式转换为另一种签名格式的功能。它确实有一个通用的ASN.1编码/解码库(用于DER和BER,尽管加密几乎完全使用DER(,它可以处理ASN.1的一半,但是你仍然必须做"普通"(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();
}

最新更新