验证智能卡中的签名

Verifying Signature in Smart Card

我正在从智能卡中读取三个值:字节数组格式的证书 myCert,字节数组格式的数据 myData 和字节数组格式的签名数据 mySignedDatamydata 的符号。然后,我使用以下代码生成证书:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(myCert);
Certificate cert = (X509Certificate) cf.generateCertificate(in);

此外,我验证myData如下:

java.security.Signature sig = java.security.Signature.getInstance("1.2.840.113549.1.1.11");
sig.initVerify(cert);
sig.update(myData);
bool verification = sig.verify(mySignedData);

但是,最后一行return这个异常:Signature encoding error 我猜这个证书的模数是不正确的。 可能是我从 myCert 生成证书的方式不正确。

此外,我应该注意到我已经通过 ACV_Cryptomanager 计算了这些值,并且我已确保输入数据有效并正确验证。

我的示例数据(全部为十六进制):

Certificate: 3082053c30820424a00302010202102edcfc1f883d4ff5a17e6f627294a4a6300d06092a864886f70d01010b0500305e310b300906035504061302495231183016060355040a0c0f4972616e20476f7665726e6d656e74310d300b060355040b0c044e4f43523126302406035504030c1d4d61746972616e20436974697a656e2043412032303135203034203133301e170d3135303431393030303030305a170d3232303431393030303030305a306a310b300906035504061302495231153013060355040b0c0c4952414e20436974697a656e31133011060355042a0c0ad986d981db8cd8b3d9873113301106035504040c0ad985d8add985d8afdb8c311a301806035504030c1130303832333931393633202d204155544830820122300d06092a864886f70d01010105000382010f003082010a0282010100c689d4e144e8539c2050833d1f8dacbad9f39e331c50b92179cc5b43125c67a166b786b81a6c59377399e55bdf5d7fca469f7690bb900cdeda03c01d1a7dc2d46c047973e9a5c0bfc5b8df4492b5f5bfe6c4d19429b9b5ae5​​8120e188a3577d0bb32e7ccebd1e0bab062907f2de6feccad5a3599637d94acc5509bacd1a02a78d39453ffbef1bdb0ffe888dfe00a4488db35a8ed8d272202f286512649ffc805f9b25eea2d667de28f9 e126745760492bdef87af4a2f6b552ab2c84b3e7a23316cb1541f85f5131f504ea579e88b922eb88c4329db82d934764aa43ddc0e9520d0b3d37d99baf16359a9a03510d685de04a49dd1382a4cb8511e44a2d904a7e10203010001a38201e8308201e4300c0603551d130101ff04023000301d0603551d0e041604146ecbb7eb04cc6b2d636fdad286d0b61513ef4b72301f0603551d23041830168014e18a6f59820c48af09659ce7096aa6c6c872c74f300e0603551d0f0101ff040403020780303a0603551d2004333031302f060a60826c651a01010265013021301f06082b060105050702011613687474703a2f2f63702e6e6f637263612e697230130603551d25040c300a06082b06010505070302301f0603551d11041830168114697230303832333931393633406972616e2e697230480603551d1f0441303f303da03ba0398637687474703a2f2f63726c64702e6e6f637263612e69722f43524c2f4d61746972616e436974697a656e434132303135303431332e63726c304e0603551d2e044730453043a041a03f863d687474703a2f2f63726c64702e6e6f637263612e69722f43524c2f4d61746972616e436974697a656e434132303135303431332e64656c74612e63726c307806082b06010505070101046c306a302106082b060105050730018615687474703a2f2f6f6 373702e6e6f637263612e6972304506082b060105050730028639687474703a2f2f706b642e6e6f637263612e69722f434143657274732f4d61746972616e436974697a656e434132303135303431332e637274300d06092a864886f70d01010b050003820101002076d4874c99806ac31541d5ea4c86cb7038a65b146d8589e31741929858f7e56b36d9639fb27d31461d50ae8b7868156a02c754f8d33405c1b091b49e7af7597e4764dfb27d392cbd4c9679f21ab21b5ba03fe6fb224db4f3a5fe23b027a8c4357d03e1bf18d1573c11ae8f2604a8fd00449a420d49c99775b575dafd81167a8e175f408221599692a3303ea5511e2cbcabd4ac1f987d2dd23387e1365f86db3f9750500c5751be9f099b468b7f120d1735058547ccaff578f553abd8abb22675279e248e0ebb0fb086cca1ada8afecf050c43fa10e0bd63718e127de69e6ba54ab5f45a97c3bf96d75234493b5f78df12215d78e2c59cceea3cf7dad20c0bc

数据:31323334353637383930

Signature: 5ab0087c861f86fde46ed64bba7f89c574070ae525293e93a6679f999e2ebd1f9a0f74398fe4f3ee5cf0216899da553d87494c60108cf0d61be0697fe7e5e6d3330ef6316ee5169297462e185a840821987ba8053a7e787808021cd3b6132060b764aa7f6067879e733c9566f032bc8fd444cb572f5304feb07a28909f6d8852834e193ee582bd7213ca1371f5cb6e314e21dab1128cf19cc64c9a9921cb5fc260793377b854f55eede5530826b9df3cabf28c35e893cef93797b531c87bda256a1a34ed82c4d92ba4c7d6f71b05f746bb164086b622b613a8b86b4e5c6d175b0171c818686739c8004027971ed83007b9bd46e0d673a84b9bc34cb5bfbff28a


generateCertificate得到的cert参数中取模的格式好奇怪:

25063151659841959529421981083752978257269678822694453669903632460321247045331466549247168429988458278533910975288361710353092929724483599744783345120140461801161963026270010094342465931161138654176753069503782925286926618486471749152769981985377799281964173100386735693992708299246126100780140210459219293374858357931333357558623770862446753445478806112484071050937869667221685659777075463240130566733596849214170678956582257108915573943791602083138661301672398645933630576523108202564418001730710531906568846648601458344275336240287160533301025959638532680212181897401162286498330482807158133244958019602980937181153

虽然指数为真:65537

好吧,你的案例最后看起来有点棘手,因为你的签名生成方式与 Signature class 不同。

为了对数据进行签名,Signature 计算其消息摘要 md,然后将 md 编码为 ASN1 序列,然后对其进行加密。另一方面,您的智能卡跳过 ASN1 编码步骤,直接加密 md,因此 java(以及 OpenSSL 也一样)无法对其进行验证。

因此,要验证这样的签名,您需要更深入地挖掘:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(myCert);
X509Certificate cert = (X509Certificate) cf.generateCertificate(in);

// calculate original message hash
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
sha256.update(myData);
byte[] md = sha256.digest();

// decrypt signature with cert's public key
Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsa.init(Cipher.DECRYPT_MODE, cert.getPublicKey());
byte[] x = rsa.doFinal(mySignedData);

// compare if results are equal
boolean verification = Arrays.equals(md, x);

现在它 returns true 对于给定值。