基于RSA算法的數字簽名技術的實現原理

xg48 9年前發布 | 61K 次閱讀 算法 安全相關

本文通過編程的方式淺析基于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

 本文由用戶 xg48 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!