2015-05-11 26 views
7

Tôi đã thử nghiệm một giải pháp để xác minh chữ ký ECDSA (How can I get a PublicKey object from EC public key bytes?) hoạt động hoàn hảo với dữ liệu đã cho.Lỗi khi xác minh chữ ký ECDSA trong Java bằng BouncyCastle

Đây là dữ liệu:

byte[] pubKey = DatatypeConverter.parseHexBinary("049a55ad1e210cd113457ccd3465b930c9e7ade5e760ef64b63142dad43a308ed08e2d85632e8ff0322d3c7fda14409eafdc4c5b8ee0882fe885c92e3789c36a7a"); 
byte[] message = DatatypeConverter.parseHexBinary("54686973206973206a75737420736f6d6520706f696e746c6573732064756d6d7920737472696e672e205468616e6b7320616e7977617920666f722074616b696e67207468652074696d6520746f206465636f6465206974203b2d29"); 
byte[] signature = DatatypeConverter.parseHexBinary("304402205fef461a4714a18a5ca6dce6d5ab8604f09f3899313a28ab430eb9860f8be9d602203c8d36446be85383af3f2e8630f40c4172543322b5e8973e03fff2309755e654"); 

Và đây là đoạn code (mà in đúng):

private static boolean isValidSignature(byte[] pubKey, byte[] message,byte[] signature) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, InvalidKeySpecException { 
    Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", new BouncyCastleProvider()); 
    ecdsaVerify.initVerify(getPublicKeyFromBytes(pubKey)); 
    ecdsaVerify.update(message); 
    return ecdsaVerify.verify(signature); 
} 

private static PublicKey getPublicKeyFromBytes(byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException { 
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1"); 
    KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider()); 
    ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN()); 
    ECPoint point = ECPointUtil.decodePoint(params.getCurve(), pubKey); 
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params); 
    ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec); 
    return pk; 
} 

public static void main (String[] args) { 
    System.out.println(isValidSignature(pubKey, message, signature)); 
} 

Vấn đề của tôi đến khi tôi thay đổi chữ ký và dữ liệu vào một ví dụ đầu vào từ hệ thống đã được triển khai:

final static byte[] pubKey = DatatypeConverter.parseHexBinary("0447303876C6FED5550DF3EE1136989FCD87293D54A5D8E2F2F6D7FBE9A81089B889A5917443AF33E696178CEF4C9D6A4288B2745B29AF6C8BCAD1348F78EB9F9B"); 
final static byte[] message = DatatypeConverter.parseHexBinary("02158001f53611a06e2d1a270000013ed9305dc2780524015110500000002d0100140092569202017aa00c5dd30000000000000000000000000000000007d1000001020001b20788b80059f48d95cdefc8c6000200200030d41e0000012016840310a50733a9870fffd0430100"); 
final static byte[] signature = DatatypeConverter.parseHexBinary("531F8918FF250132959B01F7F56FDFD9E6CA3EC2144E12A6DA37C281489A3D96"); 

đầu ra dữ liệu mới được lỗi này:

java.security.SignatureException: error decoding signature bytes. 
    at org.bouncycastle.jcajce.provider.asymmetric.util.DSABase.engineVerify(Unknown Source) 
    at java.security.Signature$Delegate.engineVerify(Signature.java:1178) 
    at java.security.Signature.verify(Signature.java:612) 
    at its.sec.exec.TestProgram.isValidSignature(TestProgram.java:168) 
    at its.sec.exec.TestProgram.execution(TestProgram.java:101) 
    at its.sec.exec.TestProgram.main(TestProgram.java:55) 

tôi giả sử vấn đề là về chữ ký mà đi kèm với các nhắn bảo đảm vì:

  • Cặp khóa là cùng độ dài và định dạng mà thí dụ. Và chính xác vì nó xuất phát từ chứng chỉ ký thông báo.
  • Bản thân thông báo (tải trọng) không ảnh hưởng đến quy trình bảo mật.

Điều cuối cùng đáng nhắc đến là tài liệu của tôi nói rằng chữ ký phải được đi trước bởi một lĩnh vực được gọi là "R" mà "chứa các tọa độ x của điểm đường cong elliptic do nhân tố tạo bởi các tin phù du khóa " và độ dài của nó phải giống với chữ ký (32 byte).

Ai đó có thể chỉ cho tôi những gì tôi thiếu ở đây không?

EDIT: Giải pháp

Như Peter Dettman chỉ trong câu trả lời của mình, signature đã không được định dạng chính xác (còn nội dung không chính xác quá) để được tính theo phương pháp verify(). Here là một lời giải thích tốt mà chủ yếu nói rằng:

When encoded in DER, this (signature) becomes the following sequence of bytes:

0x30 b1 0x02 b2 (vr) 0x02 b3 (vs)

where:

  • b1 is a single byte value, equal to the length, in bytes, of the remaining list of bytes (from the first 0x02 to the end of the encoding);
  • b2 is a single byte value, equal to the length, in bytes, of (vr);
  • b3 is a single byte value, equal to the length, in bytes, of (vs);
  • (vr) is the signed big-endian encoding of the value "r", of minimal length;
  • (vs) is the signed big-endian encoding of the value "s", of minimal length.

Áp dụng thay đổi đó, signature phát triển đến 70 byte và đầu ra thực hiện không có lỗi.

+0

Hãy coi chừng sự khác biệt giữa ASN.1 số nguyên được mã hóa DER và một số nguyên không dấu có cùng kích thước với khóa - dễ mắc lỗi liên quan đến padding trái với byte không có giá trị! –

Trả lời

6

Định dạng chữ ký ECDSA dự kiến ​​mà triển khai BC (và nhà cung cấp khác) hoạt động là chuỗi ASN.1 được mã hóa bằng DER chứa hai giá trị số nguyên rs. Định dạng chữ ký này đã được chỉ định trong ANSI X9.62. Đây là định dạng trong tập dữ liệu đầu tiên bạn cung cấp (lưu ý rằng signature là tổng cộng 70 byte).

Trong tập dữ liệu thứ hai, signature chỉ 32 byte và không phải là chuỗi ASN.1. Tôi đoán rằng giá trị này chỉ là giá trị s và thiếu giá trị r và mã hóa ASN.1 INTEGER cho cả hai, thay vào đó mã hóa các giá trị dưới dạng giá trị số nguyên lớn chưa được ký hiệu có cùng kích thước với khóa.

Các vấn đề liên quan