简体   繁体   English

无法在JAVA中验证签名,但在.NET中成功

[英]Can't verify signature in JAVA but success in .NET

We have old system using .NET 3.5 (run on Windows Server 2003 32bits) to verify e-receipts from our customers (all use SHA1RSA algorithm as agreement). 我们拥有使用.NET 3.5(运行于Windows Server 2003 32位)的旧系统来验证来自客户的电子收据(所有协议均使用SHA1RSA算法)。 We store their certificates in database in Base64 string. 我们将其证书以Base64字符串存储在数据库中。 Old code look like that: 旧代码如下所示:

//Store certificates
String certificateEncodeBase64 = Convert.ToBase64String(byteArrayCertificateFile);

//Verify signatures

//Hash algorithm SHA-1
HashAlgorithm hashAlgrothm = new SHA1Managed();
//Data
byte[] data = System.Text.Encoding.UTF8.GetBytes(request.DataInUTF8);
//Signature
byte[] signature = Convert.FromBase64String(request.SignatureInBase64);
//Certificate
X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(certEncodeBase64));
//Verify using algorithm RSA
RSACryptoServiceProvider pubKey = (RSACryptoServiceProvider)certificate.PublicKey.Key    
bool vr = pubKey.VerifyData(data, hashAlgrothm, signature);

Nothing issues except the performance is not good. 除了性能不好外没有其他问题。 That's why we want to move to new system using Java 1.7 (run on Windows Server 2012 64 bits). 这就是为什么我们要迁移到使用Java 1.7(在Windows Server 2012 64位上运行)的新系统的原因。 Our new code look like that: 我们的新代码如下所示:

//Using the same DB store certificates

//Verify signatures using Bouncy Castle JCE Provider

//Hash data using SHA-1
byte[] data_ = request.getDataInUTF8().getBytes("UTF-8");
MessageDigest messageDigest_ = MessageDigest.getInstance("SHA-1", "BC");
byte[] hashed = messageDigest.digest(data);
//Signature
byte [] signature = new BASE64Decoder().decodeBuffer(request.getSignatureInBase64());
//Certificate
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", "BC");
byte[] buffer = new BASE64Decoder().decodeBuffer(certEncodeBase64);
ByteArrayInputStream byteArrayCertificateInputStream = new ByteArrayInputStream(buffer);
Certificate certificate = certificateFactory.generateCertificate(byteArrayCertificateInputStream);
//Verify using algorithm RSA
Signature verifyEngine = Signature.getInstance("RSA", "BC");
verifyEngine.initVerify(certificate);
verifyEngine.update(hashed);
result = verifyEngine.verify(signature);

And we get this problem: In our test using all verified data taken from old system, new system verify some customer's data but some customers always return fail. 我们遇到了一个问题:在使用从旧系统中获取的所有已验证数据的测试中,新系统会验证一些客户的数据,但有些客户总是返回失败。 For one failed example 举一个失败的例子

Certificate in Base64 Base64证书

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

RawData 原始数据

<HEADER><VERSION>1.0</VERSION><SENDER_CODE>TTSP_ICB</SENDER_CODE><SENDER_NAME>He Thong Thanh toan song phuong cua Ngan hang Vietinbank</SENDER_NAME><RECEIVER_CODE>TTSP_KBA</RECEIVER_CODE><RECEIVER_NAME>He thong Thanh toan song phuong cua Kho bac Nha nuoc</RECEIVER_NAME><TRAN_CODE>103</TRAN_CODE><MSG_ID>TTSP_ICB103004203763</MSG_ID><MSG_REFID /><SEND_DATE>04-03-2014 09:03:15</SEND_DATE><ORIGINAL_CODE>TTSP_ICB</ORIGINAL_CODE><ORIGINAL_NAME>He Thong Thanh toan song phuong cua Ngan hang Vietinbank</ORIGINAL_NAME><ORIGINAL_DATE>04-03-2014 09:03:15</ORIGINAL_DATE><ERROR_CODE /><ERROR_DESC /><SPARE1 /><SPARE2 /><SPARE3 /></HEADER><BODY><MT_ID>1420110300335833</MT_ID><SEND_BANK>89201001</SEND_BANK><RECEIVE_BANK>89701002</RECEIVE_BANK><CREATED_DATE>04-03-2014 09:26:24</CREATED_DATE><CREATOR>DD740063</CREATOR><MANAGER>DD740096</MANAGER><VERIFIED_DATE>04-03-2014 09:29:41</VERIFIED_DATE><F20>1474010300001334</F20><F23B>CRED</F23B><F26T>C</F26T><F32AS1>04-03-2014</F32AS1><F32AS2>VND</F32AS2><F32AS3>324000000.00</F32AS3><F33BS1>VND</F33BS1><F33BS2>324000000.00</F33BS2><F36 /><F50P1>VND101101001</F50P1><F50AP2 /><F50KP2>HUYNH THI KIM THOA</F50KP2><F51AP1S1 /><F51AP1S2 /><F51AP2 /><F52P1S1 /><F52P1S2 /><F52AP2>89201001</F52AP2><F52DP2>89201001</F52DP2><F53P1S1 /><F53P1S2 /><F53AP2 /><F53BP2 /><F53DP2 /><F54P1S1 /><F54P1S2 /><F54AP2 /><F54BP2 /><F54DP2 /><F55P1S1 /><F55P1S2 /><F55AP2 /><F55BP2 /><F55DP2 /><F56P1S1 /><F56P1S2 /><F56AP2 /><F56CP2 /><F56DP2 /><F57P1S1>C</F57P1S1><F57P1S2 /><F57AP2>89701002</F57AP2><F57BP2 /><F57CP2 /><F57DP2>KBNN PHU TAN - AN GIANG</F57DP2><F59P1>372301048091</F59P1><F59AP2 /><F59P2>UBND XA BINH THANH DONG#####</F59P2><F70 /><F71A>SHA</F71A><F71GS1 /><F71GS2 /><F72>UBND XA BINH THANH DONG NOP TIEN XE CHUYEN BENH</F72><F77B /><F77TS1 /><F77TS2 /><F77TS3 /><F77TS4 /><F77TS5 /><F77TS6 /><F77TS7 /><F77TS8 /><F77TS9 /><F77TS10 /><F77TS11 /><F77TS12 /><F77TS13 /><F77TS14 /><F77TS15 /><F77TS16 /><F77TS17 /><F77TS18 /><F77TS20 /><F77TS19 /></BODY>

Hash data in Base64 using SHA-1 使用SHA-1在Base64中哈希数据

KLpuojRk329lb++8CFKTFADh+3c=

Signature in Base64 在Base64中签名

KWMVPKpQ8Pg3fUij9pND/me3orlplkbdNLWcH5rztMhIz0BjTN8CJJHiFrN1w1Qkih0lSl24zDE5nbYw/vo+EG3tSJzC+d/h7wkm6ad9LHt5Y0cxYRIKWSHJRbCjkOXcO/eE3KZaAZONGEVWt1bLkL3zERN11RAyZjFEzrGE7WbiLvp/51Cy5zBU/mLJts3waiEpqycjOOVNo59ICulwclhcPR+gVzcwh65oxBelI+XRbRN1PfEw5J48R6fTwmdtRzD+OJejMLHmiHUBErRNo+XG7Q5ovwY1AG2GfCOCYIOu2jYd5DD9ZDuLEMa54Uz7cy3UbciXG5/n+7GtLfGeHA==

For investigate further, we debug class DigestSignatureSpi that Bouncy Castle use to verify at line 为了进一步研究,我们调试了Bouncy Castle用来在线验证的DigestSignatureSpi类

try
{
    sig = cipher.processBlock(sigBytes, 0, sigBytes.length);

    expected = derEncode(hash);
}
catch (Exception e)
{
    return false;
}

sig is 信号是

[48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20, 40, -70, 110, -94, 52, 100, -33, 111, 101, 111, -17, -68, 8, 82, -109, 20, 0, -31, -5, 119]

while expected is 虽然预期是

[40, -70, 110, -94, 52, 100, -33, 111, 101, 111, -17, -68, 8, 82, -109, 20, 0, -31, -5, 119]

This debug show sig include expected bit (last 20 bytes). 此调试显示信号包括期望的位(最后20个字节)。

I don't know what is wrong. 我不知道怎么了 PLEASE HELP!!! 请帮忙!!! Thank you. 谢谢。

I don't think you're using the correct signature algorithm. 我认为您使用的签名算法不正确。 The documentation suggests that you should probably be using SHA1withRSA as the signature algorithm. 文档建议您可能应该使用SHA1withRSA作为签名算法。 This is further indicated by the signature vs. expected. 签名与预期进一步表明了这一点。 The "expected" value you give is the raw SHA-1 hash, whereas the signature you're providing is a PKCS#1 v1.5 DigestInfo (See RFC2313, section 10.1.2 ). 您提供的“期望”值是原始SHA-1哈希,而您提供的签名是PKCS#1 v1.5 DigestInfo(请参阅RFC2313,第10.1.2节 )。

I think you should change it to Signature verifyEngine = Signature.getInstance("NoneWithRSA"); 我认为您应该将其更改为Signature verifyEngine = Signature.getInstance("NoneWithRSA"); and it should work. 它应该工作。 As far as I rember that one returns the digest and not a DigestInfo structure. 据我所知,它返回摘要而不是DigestInfo结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM