基于RSA算法的数字签名技术的实现原理

xg48 9年前

本文通过编程的方式浅析基于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);   }  }

测试结果:

基于RSA算法的数字签名技术的实现原理

来自:http://my.oschina.net/linpz/blog/397354