问题
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