基于RSA算法的數字簽名技術的實現原理
本文通過編程的方式淺析基于RSA算法的數字簽名技術的內部實現原理。
一、數字簽名的原理
發送報文時,發送方由報文文本計算生成報文摘要,然后用自己的私鑰對這個摘要進行加密,這個加密后的摘要將作為報文的數字簽名和報文一起發送給接收方。接收到報文之后,接收方使用發送方的公鑰對報文附加的數字簽名進行解密,然后由接收到的原始報文計算出報文摘要,如果兩個摘要相同,那么接收方就能確定該數字簽名是發送方的。
二、數字簽名的實現
import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; public class RSAUtil { /** * 生成指定密鑰長度的密鑰對 */ public static KeyPair generateKeyPair(int keysize) throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(keysize, new SecureRandom()); KeyPair keyPair = generator.generateKeyPair(); return keyPair; } /** * 簽名 */ public static byte[] sign(String algorithm, byte[] data, PrivateKey privateKey) throws Exception { Signature signature = Signature.getInstance(algorithm); signature.initSign(privateKey); signature.update(data); return signature.sign(); } /** * 簽名驗證 */ public static boolean verify(String algorithm, byte[] signature, byte[] data, PublicKey publicKey) throws Exception { Signature s = Signature.getInstance(algorithm); s.initVerify(publicKey); s.update(data); return s.verify(signature); } }
三、數字簽名的過程模擬
import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; import javax.crypto.Cipher; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; public class RSAFake { public static byte[] sign(String algorithm, byte[] data, PrivateKey privateKey) throws Exception { MessageDigest digest = MessageDigest.getInstance("SHA1"); byte[] md = digest.digest(data); ASN1EncodableVector algVector = new ASN1EncodableVector(); algVector.add(new ASN1ObjectIdentifier("1.3.14.3.2.26")); algVector.add(DERNull.INSTANCE); DERSequence algSequence = new DERSequence(algVector); DEROctetString mdString = new DEROctetString(md); ASN1EncodableVector mdVector = new ASN1EncodableVector(); mdVector.add(algSequence); mdVector.add(mdString); DERSequence mdSequence = new DERSequence(mdVector); byte[] mdEncode = mdSequence.getEncoded(); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); cipher.update(mdEncode); return cipher.doFinal(); } public static boolean verify(String algorithm, byte[] signature, byte[] data, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, publicKey); cipher.update(signature); byte[] plain = cipher.doFinal(); ASN1Sequence sequence = ASN1Parser.toSequence(plain); // ASN1Sequence algSeq = (ASN1Sequence) sequence.getObjectAt(0); // ASN1ObjectIdentifier algId = (ASN1ObjectIdentifier) algSeq // .getObjectAt(0); // System.out.println(algId.getId()); DEROctetString hashString = (DEROctetString) sequence.getObjectAt(1); byte[] hash = hashString.getOctets(); MessageDigest md = MessageDigest.getInstance("SHA1"); byte[] calHash = md.digest(data); return Arrays.equals(hash, calHash); } }
import java.io.IOException; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; public class ASN1Parser { public static ASN1Sequence toSequence(byte[] der) throws IOException { return (ASN1Sequence) toObject(der); } private static ASN1Primitive toObject(byte[] der) throws IOException { ASN1Primitive obj = null; ASN1InputStream asnIn = new ASN1InputStream(der); obj = asnIn.readObject(); asnIn.close(); return obj; } }
四、測試驗證
import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class Client { byte[] data = null; PublicKey publicKey = null; PrivateKey privateKey = null; String algorithm = "SHA1WithRSA"; @Before public void init() throws Exception { data = "apple".getBytes(); KeyPair keyPair = RSAUtil.generateKeyPair(1024); publicKey = keyPair.getPublic(); privateKey = keyPair.getPrivate(); } @Test public void test1() throws Exception { byte[] signature = RSAUtil.sign(algorithm, data, privateKey); boolean result = RSAUtil.verify(algorithm, signature, data, publicKey); Assert.assertEquals(true, result); } @Test public void test2() throws Exception { byte[] signature = RSAFake.sign(algorithm, data, privateKey); boolean result = RSAFake.verify(algorithm, signature, data, publicKey); Assert.assertEquals(true, result); } @Test public void test3() throws Exception { byte[] signature = RSAUtil.sign(algorithm, data, privateKey); boolean result = RSAFake.verify(algorithm, signature, data, publicKey); Assert.assertEquals(true, result); } @Test public void test4() throws Exception { byte[] signature = RSAFake.sign(algorithm, data, privateKey); boolean result = RSAUtil.verify(algorithm, signature, data, publicKey); Assert.assertEquals(true, result); } }
測試結果:
來自:http://my.oschina.net/linpz/blog/397354
本文由用戶 xg48 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!