精华内容
下载资源
问答
  • Java实现两种方式 RSA签名, RSA签名校验通过 .keystore密钥文件实现生成密钥文件 test2.keystore相关使用通过密钥生成器实现Byte数据转换成 Hex字符串相关使用 通过 .keystore密钥文件实现 生成密钥文件 test2....

    通过 .keystore密钥文件实现

    生成密钥文件 test2.keystore

    • ./keytool -genkeypair -v -alias test2 -dname “CN=test2,OU=Wenyao,O=RnD,L=Yangpu,ST=Shanghai,C=China” -keyalg RSA -keysize 2048 -keypass 123456 -keystore d:/test2.keystore -storepass 123456 -validity 99999 -storetype JCEKS
    
    import org.springframework.util.Base64Utils;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Signature;
    import java.security.cert.Certificate;
    import static org.springframework.http.converter.FormHttpMessageConverter.DEFAULT_CHARSET;
    
    /**
     * 通过已生成的密钥文件签名类
     * */
    public class SignatureByFile {
        /** 密钥路径及文件名称*/
        private String keyStoreFilePath = "D:/test2.keystore";
        /** 密钥库口令*/
        private String keyStorePass = "123456";
        /** 密钥库算法*/
        private String keyStoreType = "JCEKS";
        /** 密钥项别名*/
        private String keyAlias = "test2";
        /** 密钥口令*/
        private String keyPass = "123456";
        /** 签名算法 [SHA256withRSA/SHA1withRSA/MD5withRSA/MD2withRSA]*/
        private String algorithm = "SHA256withRSA";
    
        /** 获取公钥*/
        public PublicKey getPublicKey(final String keyAlias) throws Exception {
            /** 指定密钥库算法创建实例*/
            final KeyStore ks = KeyStore.getInstance(keyStoreType);
            /** 指定要读取的密钥库文件, 创建文件输入流*/
            final InputStream is = new FileInputStream(keyStoreFilePath);
            /** 载入密钥库文件输入流*/
            ks.load(is, keyStorePass.toCharArray());
            /** 生成证书(X.509标准)*/
            final Certificate cert = ks.getCertificate(keyAlias);
            /** 从证书中获取公钥部分*/
            final PublicKey publicKey = cert.getPublicKey();
            return publicKey;
        }
    
        /** 获取私钥*/
        public PrivateKey getPrivateKey(final String keyAlias, final String keyAliasPass) throws Exception {
            /** 指定密钥库算法创建实例*/
            final KeyStore ks = KeyStore.getInstance(keyStoreType);
            /** 指定要读取的密钥库文件, 创建文件输入流*/
            final InputStream is = new FileInputStream(keyStoreFilePath);
            /** 载入密钥库文件输入流*/
            ks.load(is, keyStorePass.toCharArray());
            /** 通过别名和密钥口令, 从已载入的密钥库获取私钥*/
            final PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyAliasPass.toCharArray());
            return privateKey;
        }
    
        /**
         * RSA签名
         *  @param plainText 源文本
         *  @return 签名
         **/
        public String sign(final String plainText) throws Exception {
            /** 获取私钥*/
            final PrivateKey privateKey = getPrivateKey(keyAlias, keyPass);
            /** 生成签名算法实例*/
            final Signature instance = Signature.getInstance(algorithm);
            instance.initSign(privateKey);
            instance.update(plainText.getBytes(DEFAULT_CHARSET));
            final byte[] signature = instance.sign();
            return Base64Utils.encodeToString(signature);
        }
    
        /**
         * RSA签名校验
         *  @param plainText 源文本
         *  @param signedText 签名
         *  @return 签名
         **/
        public boolean verify(final String plainText, final String signedText) throws Exception {
            /** 获取公钥*/
            final PublicKey publicKey = getPublicKey(keyAlias);
            /** 生成签名算法实例*/
            final Signature instance = Signature.getInstance(algorithm);
            instance.initVerify(publicKey);
            instance.update(plainText.getBytes(DEFAULT_CHARSET));
            final byte[] signature = Base64Utils.decodeFromString(signedText);
            return instance.verify(signature);
        }
    
    }
    
    

    相关使用

    
            final String data = "签名前数据";
            final SignatureByFile signature = new SignatureByFile();
            final String signedData = signature.sign(data);
            final boolean verify = signature.verify(data, signedData);
            System.out.println(signedData);
            System.out.println(verify);
    
    > M5hgiRY30fX7zSo5i+YRpAzpLR0i7dNX1qN8cwN6Sf9JtjoCaVXUywSOz1PC3w311jXtixPMfK3B1+2R7qUlOjTOWPFBiMBqUYy4f0xXLFQw9kMDK/WTtn+nbVezHgqxtBjFNC1/nttmH7PSxhY+SV2KzU+RzC0F2tGhWm0JQQpCZuVQQzVdikJL8NBY8vdqT9SuEpFSX++f2gAQVFyro92ntye/zTbqOFr/qAhXF03CN2jGlvp7ZEbxkxqcMLSHjeTGF0VfzrLgDVpsQdh4qb3dr+tgrs1rgBsVKKiRKmsus4J7YKrjWzcgd/DZAIEozoMnDT/GOonAphRKG6VDMA==
    > true
    
    

    通过密钥生成器实现

    
    import org.springframework.util.Base64Utils;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.Signature;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import static org.springframework.http.converter.FormHttpMessageConverter.DEFAULT_CHARSET;
    
    /**
     * RSA算法签名类
     * */
    public class SignatureByRSA {
        /** 签名算法 [SHA256withRSA/SHA1withRSA/MD5withRSA/MD2withRSA]*/
        private String algorithm = "MD5withRSA";
        /** 秘钥对实例*/
        private KeyPair keyPair;
    
        /**
         * RSA签名校验
         *  @param keyalg 密钥算法 [RSA]
         *  @param keySize 密钥位大小 [1024,2048]
         * */
        public SignatureByRSA(final String keyalg, final int keySize) throws Exception {
            final KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(keyalg);
            pairGenerator.initialize(keySize);
            /** 生成秘钥对实例*/
            keyPair = pairGenerator.generateKeyPair();
        }
    
        /** 获得 RSA公钥*/
        public RSAPublicKey getPublicKey() {
            return (RSAPublicKey) keyPair.getPublic();
        }
    
        /** 获得 RSA私钥*/
        public RSAPrivateKey getPrivateKey() {
            return (RSAPrivateKey) keyPair.getPrivate();
        }
    
        /**
         * RSA签名
         *  @param plainText 源文本
         *  @return 签名
         **/
        public String sign(final String plainText) throws Exception {
            /** 生成签名算法实例*/
            final Signature instance = Signature.getInstance(algorithm);
            instance.initSign(getPrivateKey());
            instance.update(plainText.getBytes(DEFAULT_CHARSET));
            final byte[] signature = instance.sign();
            return Base64Utils.encodeToString(signature);
        }
    
        /**
         * RSA签名校验
         *  @param plainText 源文本
         *  @param signedText 签名
         *  @return 签名
         **/
        public boolean verify(final String plainText, final String signedText) throws Exception {
            /** 生成签名算法实例*/
            final Signature instance = Signature.getInstance(algorithm);
            instance.initVerify(getPublicKey());
            instance.update(plainText.getBytes(DEFAULT_CHARSET));
            final byte[] signature = Base64Utils.decodeFromString(signedText);
            return instance.verify(signature);
        }
    
    }
    
    

    Byte数据转换成 Hex字符串

    
        public static String convertBytes2HexString(final byte[] data) {
            final StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; i++) {
                String s = Integer.toHexString(0xFF & data[i]);
                if (s.length() == 1){
                    sb.append(0).append(s);
                }else {
                    sb.append(s);
                }
            }
            return sb.toString();
        }
        
    

    相关使用

    
            final String data = "签名前数据";
            final SignatureByRSA signature = new SignatureByRSA("RSA", 2048);
            final String signedData = signature.sign(data);
            final boolean verify = signature.verify(data, signedData);
            System.out.println(convertBytes2HexString(signature.getPublicKey().getEncoded()));
            System.out.println(convertBytes2HexString(signature.getPrivateKey().getEncoded()));
            System.out.println(signedData);
            System.out.println(verify);
    
    > 30820122300d06092a864886f70d01010105000382010f003082010a0282010100a0830541f5d36f87f02b2b5b4da4717fc6a6f6466f73ac6df0a6f5ac58494632f4ca6b524c96a8086e4d92fa2db90f8b74a98e4d647530974c5bb050b7eb103b3f60a29a98511ed8c14a58ca2caffa20be79f961a91daabf6311f58a9c3cf4df065b6943eea139c41fd982fca0172f6e0500d0a0fae1ec9891d488d78fb476b09aa278f2128f6cf41d0548af9057a967bf0f91405de2564221129d1a7b56ac8c6366fa507166a5549fd80c5297bb9f73add9ff2fe4d91e9c2fb0c7119762ed0f1441d1786340b8550760a9f8a752bc134754432c2ded1f6cfd8ae2a3b8a6f6febac7fbbd8201c668cdbacbde740f61fd3d3bb56c359a4e68b17054074f23d8670203010001
    > 308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100a0830541f5d36f87f02b2b5b4da4717fc6a6f6466f73ac6df0a6f5ac58494632f4ca6b524c96a8086e4d92fa2db90f8b74a98e4d647530974c5bb050b7eb103b3f60a29a98511ed8c14a58ca2caffa20be79f961a91daabf6311f58a9c3cf4df065b6943eea139c41fd982fca0172f6e0500d0a0fae1ec9891d488d78fb476b09aa278f2128f6cf41d0548af9057a967bf0f91405de2564221129d1a7b56ac8c6366fa507166a5549fd80c5297bb9f73add9ff2fe4d91e9c2fb0c7119762ed0f1441d1786340b8550760a9f8a752bc134754432c2ded1f6cfd8ae2a3b8a6f6febac7fbbd8201c668cdbacbde740f61fd3d3bb56c359a4e68b17054074f23d86702030100010282010021f5d6a4f007fe2efac78772d7e89502fddad17c71943dc53d07762f32b6be1d85e155f7a1b0b678a22dd38d0f237a807cfc6ad94109f26ff07dedbe064bbbb16d655ac1eebc2b149d40c7ac6eec04b5ecd70dc675eb8af6d7553368524a2b5d0c9146a252d8d5ca031b1835af0178cd844d79d6b57e1b7ae44fdd6c0e419662ccc1d12d019e0ca5c89b336e06a316807bdf0fd490587ed2064456c4052179b896a1943be20c3badb49670a296672b70016c1a5cae9ab09caf46a4c189cb2ceb951347ff014f865fe027e529b9f3be6768fda01c0cb969e341302b64d6bab1f06e433cbd044d92e3c1a2d29209679964ce0d9effb7a845e660631c937b060a9102818100e5b60a8d6b16f7710eb8685096c19614feedcb81ea5923025c160b7d34decc4f67310185d813d23911bc96b9b53b2f8cf2ed82d31063e718649a760f41d6e42868e57545821c1734af883e010cf297247b114ec37bc06ef002943acbda9cc97fa57e6151d594b399dd31da14cf962ce713ff3c5fe4b7b03019fa5a3e0dcb3de502818100b2e19d0d0dc512bdb4d02e390d48960b8d7146f36f6aefeced4d4478c22d03769e4ece695ede8da73332125c74e0557a735c850ff8b15850cd5a1c211e8d7fa32bbb885b0792732108f0f3d21a8d2f9ea52d09b879a70c0cac075f3184c39a1bc9db2dee41ec841b2e010ea5a425da6db8595d969660c2f30519a553fd43f85b0281806cccf168941d77abcbfe1a2279954d81ba51653fae80f3ad0d72bf94593361f005ff572a4ef2ec726d6d36b2d51d2863893867eb926acf2d65912774088a40dcc6fa4fb6516efeaaccad2a391329dfdebe8faf0fb610aa3af1edc57f82971a75642c5cea06d07cd4d6c8e2f352735de74138761f3154b395c4e8285015f67ae50281810098724611d5e659ee6aa5f07e969f81a01ecea714d7a35f0d9fbef5d7a444106b8ac6c68a6e5b648555d01a6dc8fd565ba0ecfc497c3c4773b54e5222b793076fdbd95a7f9998699d81ad375d9b5b2f761876a58e1dbf0b39d17206e280aee22b44801248b6ce0657d380fb269719db691e6eaa9fa7509753dcc8da6915b253790281800f5db934ef6397c6081583ba35732fd8808fd9d955debbb3cfd013dde14c4bdef29dbe8577c865f7c6fb2696c55a44edef90a89b6c35969154376898dd120224218885070fb26d300837c34335052723cf44ab3d609f8ccc7430eb1e1e6e44028aa26d334c48ba426cef2cb1f78125fbe681e62f27dba8544cd9c9b2d838bef9
    hoJghoDi0WDNDcmsEyED1LNoaRTnZRD439v8tBlUimeKuBezrVH7fS7iTqyyCgBc+X6cdgk4pMo7eIMEBt+JwqBlKhjpdJZXQUHSbZQG7D+MGSXk9Ip5/FCIf3Y2NBc3Y5dHiqYVy0vQ5QClj8QK0l8hPZKUuvXSHHWNo72tF7OHkqdy/gysmVRbul3Kyt/QqA7CVU4d9IkNOoePlvqYcZeAdx2yIDisS0jR+RnsrKM2UuRrRJRMaPpRcxtYz/tqnvr/x4ZeUvLT85XZZAf9pL/Me2XwmN3D5i7tyuKKG/bftMS65YOyNvFD0Kytd9fAoOaeMVilfos9R4C3rjSh1w==
    > true
    
    

    如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

    展开全文
  • 本资源包含:RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。 RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977...
  • python RSA签名

    千次阅读 2015-06-14 08:08:53
    python 使用pycrypto来做RSA签名

    这周一个项目客户提供了一份对接文档要求用RSA数字签名,客户提供的是java的demo,但是自己不想用java来做,想用python来实现,就自己研究了下python下RSA签名。


    先是研究了java-demo的流程和逻辑(因为是公司项目客户提供的,不便对外公开),基本的流程是这样的:

    1)先根据私钥KEY字符串,获取私钥对象(PrivateKey)

    私钥KEY----------就是一个长字符串

    比如下面这个是我自己用openssl生成的(MIIEpQIBAAKCAQEA9JPHRFaWOhi7PXZz/Kmun/ldJrd+YQy6diU2eFijVooL8NDG
    4dsOojUpT9FhAUedXcDZrYN3BstFcaGRJQouyXZsbJjyFL8WNLLGFIwdcv1pTGve
    cLOEdU1Rl+E4wCznYflxcUN3ngZQo7cN/la2poM1k/epR8UsWiH8wQj+v7FHMrt4
    XMhVSVAqslfhs6yqJQuQwu3YiaspZVySAywaFFveLCcedKPrlZYoN9Q1Qg7hyXZ+
    hqIPIyXBHFU721GqlDJ8K6lCXxjNK7xFWwo1QzLAwdfLA0ZJ1K00+4nv9E1JUcbX
    emhDJHvyZ9O/ExRqdykkE6CAJD3tZkjhQwERnwIDAQABAoIBABQVxrl/+tpOiaHk
    hmXrcWHF0raJPyGtL+rf53c+oDtNHunp20tU+ACuKPRbF4JJZUz7t2SedTnjm5JX
    WFoYWftFdGX+sXKutp4hSE8Lqqd01B7ohN3wgCI59UdpwYVWqrHLEFvi1IHvttOb
    BtUqPdmy0MWUAxzXvmqwe9dGa9VGCp55HezZo0nDkwg8s7h/CKndxmGCvFX/O5iV
    RaJgUOkQ9iRp8v1M3ri/XBvt1BmAUzFvXs3RNmF3/fKsvOCINFIGnZt+zyW7s7XA
    RBgOluorDLdMusvxy9qrGspc3U8L6Uf7xsHKwvaAVD/RLP03FopNkg8HPphikbQA
    naoWzKECgYEA/giQ3qSJfNH/0TELayYVzEq3MYOEc/tiI1YrUUXLTJ7rQ3yZSjt7
    HMIgjPzO6Ek4iVdVX0QnNNvD9To40blr5KykeIoAOyta7hEAvZS4uMue1YXkW8i2
    YpQJ9BzNho0SpHyB13/7TT9l9kyNSqemOVrDfvo24d4S7YafhBiNXOkCgYEA9nh4
    +GCmV6+XR7lwbMrp3JLE/xpyiGK8P27COT22pT9Q3in8BSgjMa+vmJnGase6oQr6
    xcd5Odqg5YmCs+T2MLoJg0sSBfCJxASRZPDnpz2MjTordm09PkauOCSsoq1IhH5E
    xkDw97zIm1m1h87W8Zd+E500E687vRBanEzFxUcCgYEAwdwNmiqcVWn4vE6eNSW6
    Ss3V4W5JPS1g5jCTHBGUJKO+TCEg5hpgSEEJEC65Q2DlSUIhf3MGLHttno3Q4JOM
    99ScKvS9WmoqmTTWiNae5T9WtgHYlAam0LHCqsz0NzMfP/FYMPmU8I1qJTykMo2f
    93MBb7xI97M+ZI9w2iDWeEkCgYEAu5G1ZjiPfv3XYDNE1taZoU5k80taTGbvokqV
    LuDDZgDIdzp2XCpOllqAhN7KPKshYbusWuXSYO/8MJM0z9j4bt61rKBt5+1FutJL
    IAmiEglqNHRHbUn3KLS7k2h9pRPAs2wwxLvZZn/aHzfnSaJku9kxjpW9cxmRmfGf
    M4HNpLMCgYEAppL5J9jja2DrkRXoS9d4MvwaTlF/HsY2QRVRmlcvZddKXECcJ/fI
    wmP7V/NNegLBsMukdrPez28bK1ci0iigO6dCjxnUZF1KDPzLwgsNG2Z9i54nsmOT
    7xwfITqzE3gA2NSRNVY7oo8pwfGU1kEeySrMUxrRZ3EaerTS0JSIdSg=)


    注意java提供的私钥KEY字符串是不包括开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的。


    因为openssl默认产生的PEM格式的是包括开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的


    根据提供的私钥KEY字符,demo中得到一个私钥对象(PrivateKey)。

    下面是java得到私钥对象的代码:

    public static PrivateKey getPrivateKey(String key) {
    try {
    byte[] keyBytes = (Base64.decodeBase64(key));
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
    return privateKey;
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    }

    2)根据得到的私钥对象(PrivateKey),得到给定字符串的签名

    public String sign(byte[] data, PrivateKey priKey) {
    try {
    Signature signature = Signature.getInstance("MD5WithRSA");
    signature.initSign(priKey);
    signature.update(data);
    return Base64.encodeBase64URLSafeString(signature.sign());
    } catch (Exception e) {
    return null;
    }
    }


    上面是java中的RSA的基本的流程,这里还有个验签的步骤,这里就不说了。


    下面讲一下我在python中的使用,网上找了很多,也吸取了很多有用的东西,一开始用M2Crypto来做,这个库可以用pip install M2Crypto获取,但是这个库是依赖openssl的,先得安装openssl,我下得得官网得openssl-0.9.8-stable-SNAP-20150609.tar.gz,然后还得安装Perl,具体教程可以参考(http://www.cnblogs.com/ZhouL3777/archive/2012/10/21/2732890.html),我M2Crypto完全安装成功后,后面可能是我使用的问题,签名出来的字符串跟java签名出来的不一样,这个地方以后有空再深入研究下。后面讲下重点,使用pycrypto库。


    使用pycrypto来做RSA签名:

    1.因为pyCrypto库不依赖openssl库,所以直接pip install pycrypto 就可以安装成功(我的python2.7.9,pycrypto版本是2.6.1)


    2.签名函数:

    '''
    RSA签名
    '''
    def sign(signdata):
        '''
        @param signdata: 需要签名的字符串
        '''
    
        h=MD5.new(signdata)
        signer = pk.new(RSA.importKey(p))
        signn=signer.sign(h)
        # signn=base64.b64encode(signn,["-","_"])
        signn=base64.urlsafe_b64encode(signn)
        return signn

    关键介绍下函数中p,这个是私钥字符串,但是开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----得加上。


    我用客户提供的私钥字符串(不含开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的),然后p是加上开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的值。


    # signn=base64.b64encode(signn,["-","_"])
        signn=base64.urlsafe_b64encode(signn)
    这两个其实是一样的效果,把“+”转成“-”,把“/”转成“_”而已。


    这样签名出来的跟java签名出来的东西一样了, 但是最后多了一个“=”。 这个我不知道为什么会多了一个“=”。  如果哪位高手知道,解释一下。


    写的有点凌乱啊,望看的见谅。

    展开全文
  • RSA签名与验签

    千次阅读 2017-06-20 09:07:33
    RSA签名与验签RSA算法除了可以进行加解密以外,还可以用来签名与验签。RSA用来进行签名与验签时是使用私钥进行签名,公钥进行验签的。这点与加解密的时候刚好相反。加解密时使用公钥加密,私钥解密。签名和验签是...


    RSA签名与验签

    RSA算法除了可以进行加解密以外,还可以用来签名与验签。RSA用来进行签名与验签时是使用私钥进行签名,公钥进行验签的。这点与加解密的时候刚好相反。加解密时使用公钥加密,私钥解密。签名和验签是通过Signature对象进行的。

    签名

    以下是一个使用Signature进行签名的示例。初始化Signature时指定将使用的签名算法是MD5withRSA,除了该算法外,Signature还支持很多其它的算法,如SHA256withRSA,更多的算法可以参考官方文档

    	/**
    	 * 测试签名
    	 * @throws Exception
    	 */
    	@Test
    	public void testSign() throws Exception {
    		byte[] sign = this.sign("Hello World");
    		String result = Base64.getEncoder().encodeToString(sign);
    		System.out.println(result);
    	}
    	
    	/**
    	 * 私钥签名
    	 * @param data
    	 * @return
    	 * @throws Exception
    	 */
    	private byte[] sign(String data) throws Exception {
    		//读取储存的私钥字节数组
    		byte[] privateKeyCode = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH));
    		//包装私钥字节数组为一个KeySpec
    		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyCode);
    		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
    		//通过KeyFactory生成私钥
    		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
    		Signature signature = Signature.getInstance("MD5withRSA");//签名的算法
    		//通过私钥初始化Signature,签名时用
    		signature.initSign(privateKey);
    		//指定需要进行签名的内容
    		signature.update(data.getBytes());
    		//签名
    		byte[] result = signature.sign();
    		return result;
    	}

    验签

    以下是一个利用Signature进行验签的示例。验签时使用的是公钥。在初始化Signature时使用的是initVerify,而签名时使用的是initSign,这跟Cipher进行加解密有点类似。

    	/**
    	 * 测试公钥验签
    	 * @throws Exception
    	 */
    	@Test
    	public void testVerifySign() throws Exception {
    		String data = "Hello World";
    		byte[] sign = this.sign(data);
    		Signature signature = Signature.getInstance("MD5withRSA");
    		byte[] publicKeyCode = Files.readAllBytes(Paths.get(PUBLIC_KEY_PATH));
    		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyCode);
    		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
    		PublicKey publicKey = keyFactory.generatePublic(keySpec);
    		//以验签的方式初始化Signature
    		signature.initVerify(publicKey);
    		//指定需要验证的签名
    		signature.update(data.getBytes());
    		//进行验签,返回验签结果
    		boolean result = signature.verify(sign);
    		Assert.assertTrue(result);
    	}

    完整代码 以下是上述示例的完整代码。

    public class RSATest {
    
    	private static final String ALGORITHM = "RSA";
    	private static final String PRIVATE_KEY_PATH = "D:\\rsa_private.isa";
    	private static final String PUBLIC_KEY_PATH = "D:\\rsa_public.isa";
    	
    	/**
    	 * 测试签名
    	 * @throws Exception
    	 */
    	@Test
    	public void testSign() throws Exception {
    		byte[] sign = this.sign("Hello World");
    		String result = Base64.getEncoder().encodeToString(sign);
    		System.out.println(result);
    	}
    	
    	/**
    	 * 私钥签名
    	 * @param data
    	 * @return
    	 * @throws Exception
    	 */
    	private byte[] sign(String data) throws Exception {
    		//读取储存的私钥字节数组
    		byte[] privateKeyCode = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH));
    		//包装私钥字节数组为一个KeySpec
    		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyCode);
    		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
    		//通过KeyFactory生成私钥
    		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
    		Signature signature = Signature.getInstance("MD5withRSA");//签名的算法
    		//通过私钥初始化Signature,签名时用
    		signature.initSign(privateKey);
    		//指定需要进行签名的内容
    		signature.update(data.getBytes());
    		//签名
    		byte[] result = signature.sign();
    		return result;
    	}
    	
    	/**
    	 * 测试公钥验签
    	 * @throws Exception
    	 */
    	@Test
    	public void testVerifySign() throws Exception {
    		String data = "Hello World";
    		byte[] sign = this.sign(data);
    		Signature signature = Signature.getInstance("MD5withRSA");
    		byte[] publicKeyCode = Files.readAllBytes(Paths.get(PUBLIC_KEY_PATH));
    		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyCode);
    		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
    		PublicKey publicKey = keyFactory.generatePublic(keySpec);
    		//以验签的方式初始化Signature
    		signature.initVerify(publicKey);
    		//指定需要验证的签名
    		signature.update(data.getBytes());
    		//进行验签,返回验签结果
    		boolean result = signature.verify(sign);
    		Assert.assertTrue(result);
    	}
    	
    }
    

    (注:本文由Elim写于2017年5月22日)

    展开全文
  • RSA签名和验签

    千次阅读 2019-03-06 17:10:31
    由于RSA算法相对于对称加密算来说效率较低,通常RSA算法用来加密小数据,如对称加密使用...一、RSA签名 RSA算法的签名和验签操作本质上来讲也是大数的模幂运算,RSA算法的安全性很大程度上取决于填充方式,因此在一...

    由于RSA算法相对于对称加密算来说效率较低,通常RSA算法用来加密小数据,如对称加密使用的key等。实际上应用更为广泛的是RSA算法用在签名操作上。通常使用私钥对一段消息的hash值进行签名操作,达到消息的防篡改和伪造。这里就来介绍一下RSA算法是如何应用到签名领域的。

    一、RSA签名

    RSA算法的签名和验签操作本质上来讲也是大数的模幂运算,RSA算法的安全性很大程度上取决于填充方式,因此在一个安全的RSA加密操作需要选择一个合适的填充模式,因此签名的运算同样需要选择合适的padding方式,下面以代码为例,来介绍下RSA算法签名的过程。可以看到这里主要有两种padding方式,一种是PKCS_V15,另外一种是PKCS_V21(PSS)。

    /*
     * Do an RSA operation to sign the message digest
     */
    int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
                        int (*f_rng)(void *, unsigned char *, size_t),
                        void *p_rng,
                        int mode,
                        mbedtls_md_type_t md_alg,
                        unsigned int hashlen,
                        const unsigned char *hash,
                        unsigned char *sig )
    {
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
        RSA_VALIDATE_RET( sig != NULL );
    
        switch( ctx->padding )
        {
    #if defined(MBEDTLS_PKCS1_V15)
            case MBEDTLS_RSA_PKCS_V15:
                return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg,
                                                  hashlen, hash, sig );
    #endif
    
    #if defined(MBEDTLS_PKCS1_V21)
            case MBEDTLS_RSA_PKCS_V21:
                return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg,
                                            hashlen, hash, sig );
    #endif
    
            default:
                return( MBEDTLS_ERR_RSA_INVALID_PADDING );
        }
    }

    首先在进行签名操作时,根据不同的padding方式选择不同的签名运算函数。

    如果选择的是PKCS_V15填充模式,则会调用mbedtls_rsa_rsaes_pkcs1_v15_sign函数进行签名运算。此模式的padding方式可以用如下公式表示EB=00||BT||PS||00||D。其中开头的00是为了防止做加密运算的padding后数据大于模指数N;BT是Block Type的缩写,代表块的的类型,如果是私钥操作的话,这里是字节0x00或者0x01,如果是公钥操作的话,这里是0x02。PS是的Padding String的缩写。它的长度至少是8字节,大小等于K(Key size in byte)-3-D,如果这里BT是0x01,这里的padding是K-3-D字节0xff,如果BT是0x02,这里的padding是K-3-D字节的随机数。做完填充之后,进行最基本的RSA模幂运算。根据mode类型,选择是公钥还是私钥运算。

    /*
     * Do an RSA operation to sign the message digest
     */
    int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
                                   int (*f_rng)(void *, unsigned char *, size_t),
                                   void *p_rng,
                                   int mode,
                                   mbedtls_md_type_t md_alg,
                                   unsigned int hashlen,
                                   const unsigned char *hash,
                                   unsigned char *sig )
    {
        int ret;
        unsigned char *sig_try = NULL, *verif = NULL;
    
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
        RSA_VALIDATE_RET( sig != NULL );
    
        if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        /*
         * Prepare PKCS1-v1.5 encoding (padding and hash identifier)
         */
    
        if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash,
                                                 ctx->len, sig ) ) != 0 )
            return( ret );
    
        /*
         * Call respective RSA primitive
         */
    
        if( mode == MBEDTLS_RSA_PUBLIC )
        {
            /* Skip verification on a public key operation */
            return( mbedtls_rsa_public( ctx, sig, sig ) );
        }
    
        /* Private key operation
         *
         * In order to prevent Lenstra's attack, make the signature in a
         * temporary buffer and check it before returning it.
         */
    
        sig_try = mbedtls_calloc( 1, ctx->len );
        if( sig_try == NULL )
            return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
    
        verif = mbedtls_calloc( 1, ctx->len );
        if( verif == NULL )
        {
            mbedtls_free( sig_try );
            return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
        }
    
        MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
        MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) );
    
        if( mbedtls_safer_memcmp( verif, sig, ctx->len ) != 0 )
        {
            ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
            goto cleanup;
        }
    
        memcpy( sig, sig_try, ctx->len );
    
    cleanup:
        mbedtls_free( sig_try );
        mbedtls_free( verif );
    
        return( ret );
    }

    如果选择的是PKCS_V21填充模式,则会调用mbedtls_rsa_rsasa_pss_sign函数进行加密运算。

    此模式的padding方式可以用如下公式表示EM=PS||MaskedDB||hash||0xBC。

    其中MaskedDB是DB异或dbmask的结果,

    dbmask=MGF(mhash),

    mhash=hash(0x00||messagehash||salt),其中message是要签名的消息,messagehash是要签名消息的摘要。

    待消息填充完成之后,根据使用的秘钥类型来选择相应的加密函数,进行签名运算。

    *
     * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
     */
    int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
                             int (*f_rng)(void *, unsigned char *, size_t),
                             void *p_rng,
                             int mode,
                             mbedtls_md_type_t md_alg,
                             unsigned int hashlen,
                             const unsigned char *hash,
                             unsigned char *sig )
    {
        size_t olen;
        unsigned char *p = sig;
        unsigned char salt[MBEDTLS_MD_MAX_SIZE];
        size_t slen, min_slen, hlen, offset = 0;
        int ret;
        size_t msb;
        const mbedtls_md_info_t *md_info;
        mbedtls_md_context_t md_ctx;
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
        RSA_VALIDATE_RET( sig != NULL );
    
        if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        if( f_rng == NULL )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        olen = ctx->len;
    
        if( md_alg != MBEDTLS_MD_NONE )
        {
            /* Gather length of hash to sign */
            md_info = mbedtls_md_info_from_type( md_alg );
            if( md_info == NULL )
                return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
            hashlen = mbedtls_md_get_size( md_info );
        }
    
        md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
        if( md_info == NULL )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        hlen = mbedtls_md_get_size( md_info );
    
        /* Calculate the largest possible salt length. Normally this is the hash
         * length, which is the maximum length the salt can have. If there is not
         * enough room, use the maximum salt length that fits. The constraint is
         * that the hash length plus the salt length plus 2 bytes must be at most
         * the key length. This complies with FIPS 186-4 §5.5 (e) and RFC 8017
         * (PKCS#1 v2.2) §9.1.1 step 3. */
        min_slen = hlen - 2;
        if( olen < hlen + min_slen + 2 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
        else if( olen >= hlen + hlen + 2 )
            slen = hlen;
        else
            slen = olen - hlen - 2;
    
        memset( sig, 0, olen );
    
        /* Generate salt of length slen */
        if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
            return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
    
        /* Note: EMSA-PSS encoding is over the length of N - 1 bits */
        msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
        p += olen - hlen - slen - 2;
        *p++ = 0x01;
        memcpy( p, salt, slen );
        p += slen;
    
        mbedtls_md_init( &md_ctx );
        if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
            goto exit;
    
        /* Generate H = Hash( M' ) */
        if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 )
            goto exit;
        if( ( ret = mbedtls_md_update( &md_ctx, p, 8 ) ) != 0 )
            goto exit;
        if( ( ret = mbedtls_md_update( &md_ctx, hash, hashlen ) ) != 0 )
            goto exit;
        if( ( ret = mbedtls_md_update( &md_ctx, salt, slen ) ) != 0 )
            goto exit;
        if( ( ret = mbedtls_md_finish( &md_ctx, p ) ) != 0 )
            goto exit;
    
        /* Compensate for boundary condition when applying mask */
        if( msb % 8 == 0 )
            offset = 1;
    
        /* maskedDB: Apply dbMask to DB */
        if( ( ret = mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen,
                              &md_ctx ) ) != 0 )
            goto exit;
    
        msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
        sig[0] &= 0xFF >> ( olen * 8 - msb );
    
        p += hlen;
        *p++ = 0xBC;
    
        mbedtls_platform_zeroize( salt, sizeof( salt ) );
    
    exit:
        mbedtls_md_free( &md_ctx );
    
        if( ret != 0 )
            return( ret );
    
        return( ( mode == MBEDTLS_RSA_PUBLIC )
                ? mbedtls_rsa_public(  ctx, sig, sig )
                : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
    }

    二、RSA验签

    验签是签名的逆运算,在理解了签名操作之前再来看验签是非常容易的。验签操作会调用如下的mbedtls_rsa_pkcs1_verify函数,此函数制作一件事,就是根据ctx-->padding的类型来选择对应的验签函数。

    /*
     * Do an RSA operation and check the message digest
     */
    int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
                          int (*f_rng)(void *, unsigned char *, size_t),
                          void *p_rng,
                          int mode,
                          mbedtls_md_type_t md_alg,
                          unsigned int hashlen,
                          const unsigned char *hash,
                          const unsigned char *sig )
    {
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( sig != NULL );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
    
        switch( ctx->padding )
        {
    #if defined(MBEDTLS_PKCS1_V15)
            case MBEDTLS_RSA_PKCS_V15:
                return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg,
                                                    hashlen, hash, sig );
    #endif
    
    #if defined(MBEDTLS_PKCS1_V21)
            case MBEDTLS_RSA_PKCS_V21:
                return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg,
                                              hashlen, hash, sig );
    #endif
    
            default:
                return( MBEDTLS_ERR_RSA_INVALID_PADDING );
        }
    }

    首先,如果padding方式选择的是PKCS_V15,则会调用mbedtls_rsa_rsassa_pkcs1_v15_verify函数来验签。pkcsv15的padding是确定性固定填充,verify的过程本质上来讲是将公钥应用于签名得到padding后的包含mhash的数据。因此,本函数的逻辑是首先根据mhash通过padding得到expected_encode msg,然后通过验签得到实际的encode msg,对两个buf进行比较已达到验证签名的目的。

    /*
     * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
     */
    int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx,
                                     int (*f_rng)(void *, unsigned char *, size_t),
                                     void *p_rng,
                                     int mode,
                                     mbedtls_md_type_t md_alg,
                                     unsigned int hashlen,
                                     const unsigned char *hash,
                                     const unsigned char *sig )
    {
        int ret = 0;
        size_t sig_len;
        unsigned char *encoded = NULL, *encoded_expected = NULL;
    
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( sig != NULL );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
    
        sig_len = ctx->len;
    
        if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        /*
         * Prepare expected PKCS1 v1.5 encoding of hash.
         */
    
        if( ( encoded          = mbedtls_calloc( 1, sig_len ) ) == NULL ||
            ( encoded_expected = mbedtls_calloc( 1, sig_len ) ) == NULL )
        {
            ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
            goto cleanup;
        }
    
        if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, sig_len,
                                                 encoded_expected ) ) != 0 )
            goto cleanup;
    
        /*
         * Apply RSA primitive to get what should be PKCS1 encoded hash.
         */
    
        ret = ( mode == MBEDTLS_RSA_PUBLIC )
              ? mbedtls_rsa_public(  ctx, sig, encoded )
              : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, encoded );
        if( ret != 0 )
            goto cleanup;
    
        /*
         * Compare
         */
    
        if( ( ret = mbedtls_safer_memcmp( encoded, encoded_expected,
                                          sig_len ) ) != 0 )
        {
            ret = MBEDTLS_ERR_RSA_VERIFY_FAILED;
            goto cleanup;
        }
    
    cleanup:
    
        if( encoded != NULL )
        {
            mbedtls_platform_zeroize( encoded, sig_len );
            mbedtls_free( encoded );
        }
    
        if( encoded_expected != NULL )
        {
            mbedtls_platform_zeroize( encoded_expected, sig_len );
            mbedtls_free( encoded_expected );
        }
    
        return( ret );
    }

    如果选择的padding 模式是PKCSV21(pss模式),则验签的过程相对复杂。首先会调用mbedtls_rsa_rsassa_pss_verify函数,此函数的实现较为简单,仅仅是获取了pss填充模式使用的hash函数类型,然后作为参数传给实际的verify函数mbedtls_rsa_rsassa_pss_verify_ext。

    /*
     * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function
     */
    int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx,
                               int (*f_rng)(void *, unsigned char *, size_t),
                               void *p_rng,
                               int mode,
                               mbedtls_md_type_t md_alg,
                               unsigned int hashlen,
                               const unsigned char *hash,
                               const unsigned char *sig )
    {
        mbedtls_md_type_t mgf1_hash_id;
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( sig != NULL );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
    
        mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE )
                                 ? (mbedtls_md_type_t) ctx->hash_id
                                 : md_alg;
    
        return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode,
                                           md_alg, hashlen, hash,
                                           mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY,
                                           sig ) );
    
    }

    mbedtls_rsa_rsassa_pss_verify_ext函数的实现代码如下,这里的verify逻辑如下。

    首先使用公钥解出签名,验证encode后的数据最后一个字节是否是0xBC。

    然后对message hash做MGF运算得到DBmask=MGF(mhash)。

    将MaskedDB和DBmask进行异或运算得到DB,并从DB中恢复出salt。

    填充得到message=padding(8 Bytes 0x00)||mhash||salt。

    计算得到hash=hash(message)。

    和验签得到的hash进行比较,比较成功则签名验证成功。

    /*
     * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
     */
    int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx,
                                   int (*f_rng)(void *, unsigned char *, size_t),
                                   void *p_rng,
                                   int mode,
                                   mbedtls_md_type_t md_alg,
                                   unsigned int hashlen,
                                   const unsigned char *hash,
                                   mbedtls_md_type_t mgf1_hash_id,
                                   int expected_salt_len,
                                   const unsigned char *sig )
    {
        int ret;
        size_t siglen;
        unsigned char *p;
        unsigned char *hash_start;
        unsigned char result[MBEDTLS_MD_MAX_SIZE];
        unsigned char zeros[8];
        unsigned int hlen;
        size_t observed_salt_len, msb;
        const mbedtls_md_info_t *md_info;
        mbedtls_md_context_t md_ctx;
        unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
    
        RSA_VALIDATE_RET( ctx != NULL );
        RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE ||
                          mode == MBEDTLS_RSA_PUBLIC );
        RSA_VALIDATE_RET( sig != NULL );
        RSA_VALIDATE_RET( ( md_alg  == MBEDTLS_MD_NONE &&
                            hashlen == 0 ) ||
                          hash != NULL );
    
        if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        siglen = ctx->len;
    
        if( siglen < 16 || siglen > sizeof( buf ) )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        ret = ( mode == MBEDTLS_RSA_PUBLIC )
              ? mbedtls_rsa_public(  ctx, sig, buf )
              : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf );
    
        if( ret != 0 )
            return( ret );
    
        p = buf;
    
        if( buf[siglen - 1] != 0xBC )
            return( MBEDTLS_ERR_RSA_INVALID_PADDING );
    
        if( md_alg != MBEDTLS_MD_NONE )
        {
            /* Gather length of hash to sign */
            md_info = mbedtls_md_info_from_type( md_alg );
            if( md_info == NULL )
                return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
            hashlen = mbedtls_md_get_size( md_info );
        }
    
        md_info = mbedtls_md_info_from_type( mgf1_hash_id );
        if( md_info == NULL )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        hlen = mbedtls_md_get_size( md_info );
    
        memset( zeros, 0, 8 );
    
        /*
         * Note: EMSA-PSS verification is over the length of N - 1 bits
         */
        msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
    
        if( buf[0] >> ( 8 - siglen * 8 + msb ) )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
    
        /* Compensate for boundary condition when applying mask */
        if( msb % 8 == 0 )
        {
            p++;
            siglen -= 1;
        }
    
        if( siglen < hlen + 2 )
            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
        hash_start = p + siglen - hlen - 1;
    
        mbedtls_md_init( &md_ctx );
        if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
            goto exit;
    
        ret = mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx );
        if( ret != 0 )
            goto exit;
    
        buf[0] &= 0xFF >> ( siglen * 8 - msb );
    
        while( p < hash_start - 1 && *p == 0 )
            p++;
    
        if( *p++ != 0x01 )
        {
            ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
            goto exit;
        }
    
        observed_salt_len = hash_start - p;
    
        if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY &&
            observed_salt_len != (size_t) expected_salt_len )
        {
            ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
            goto exit;
        }
    
        /*
         * Generate H = Hash( M' )
         */
        ret = mbedtls_md_starts( &md_ctx );
        if ( ret != 0 )
            goto exit;
        ret = mbedtls_md_update( &md_ctx, zeros, 8 );
        if ( ret != 0 )
            goto exit;
        ret = mbedtls_md_update( &md_ctx, hash, hashlen );
        if ( ret != 0 )
            goto exit;
        ret = mbedtls_md_update( &md_ctx, p, observed_salt_len );
        if ( ret != 0 )
            goto exit;
        ret = mbedtls_md_finish( &md_ctx, result );
        if ( ret != 0 )
            goto exit;
    
        if( memcmp( hash_start, result, hlen ) != 0 )
        {
            ret = MBEDTLS_ERR_RSA_VERIFY_FAILED;
            goto exit;
        }
    
    exit:
        mbedtls_md_free( &md_ctx );
    
        return( ret );
    }

     

    展开全文
  • RSA签名与RSA加密异同

    千次阅读 2018-11-19 19:35:55
    RSA签名体制。签名体制同样包含3个算法:KeyGen(密钥生成算法),Sign(签名算法),Verify(验证算法). 私钥用于对数据进行签名,公钥用于对签名进行验证。 import org.apache.commons.codec.binary.Base64; ...
  • Python的RSA签名

    千次阅读 2017-10-22 12:21:37
    Python的rsa签名方法 需要安装pycrypto pip install pycrypto python代码 #!-*- coding:utf-8 -*- from Crypto.PublicKey import RSA from Crypto.Hash import MD5 from Crypto.Signature import PKCS1_v1_5 as pk...
  • RSA签名验签工具

    2018-01-26 14:43:05
    支付宝最新版的签名验签工具 支持RSA RSA2 MD5 ,生成 效验秘钥等
  • RSA签名的PSS模式

    2019-02-14 11:41:50
    本文由云+社区发表 作者:mariolu 一、什么是PSS模式? ...目前主流的RSA签名包括RSA-PSS和RSA-PKCS#1 v1.5。相对应PKCS(Public Key Cryptography Standards)是一种能够自我从签名,而PSS...
  • python实现RSA签名与验签

    千次阅读 2019-04-28 23:59:13
    RSA是一种非对称加密算法,简单理解就是两个密钥:一个公钥,一个私钥。 可以用来加解密,也可以用来签名和验签 加密:公钥加密,私钥解密;... """RSA签名和验签""" @classmethod def data_processing(...
  • Java 实现RSA签名和加密

    千次阅读 2019-09-30 17:10:03
    Java 实现RSA签名和加密 RSA在1977年发明,是公钥加密方式的事实标准,名称有其三位作者首字母组成。本文我们介绍Java中如何使用RSA实现加密和签名。 RSA属于非对称加密算法,有两个密钥。区别于共享密钥的对称加密...
  • PHP的RSA签名

    2017-10-25 09:43:58
    PHP的RSA签名 $private_content="-----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBALecq3BwAI4YJZwhJ+snnDFj3lF3DMqNPorV6y5ZKXCiCMqj8OeOmxk4YZW9aaV9 ckl/zlAOI0mpB3pDT+Xlj2sCAwEAAQJAW6/aVD05qbsZHMvZuS2Aa
  • RSA 签名-PKCS1

    千次阅读 2019-11-22 14:23:24
    针对于RSA签名来说,首先需要公钥,私钥 我现在用的是PKCS1格式的公钥私钥,也就是密钥格式为非Java适用的 1:生成公钥私钥,我直接使用的是支付宝官网上下载的RSA签名/验签的工具。 string privateKeyPem = ...
  • RSA签名和验签说明

    2020-09-08 10:08:35
    最近遇到一个项目,需要进行RSA的验签,RSA的密钥为2048位即256个字节长。 上游是先对一个文件进行SHA256做hash,得到32字节的摘要,然后进行填充,填充规则为...一、RSA签名算法的填充方式,常用的有如下三种 1、R
  • golang 使用RSA签名和验签 当前主要有两种形式base64和hex: base64 1.rsa类型签名 import ( "crypto/rsa" "crypto/rand" ) signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), ...
  • 给APP增加RSA签名

    千次阅读 2015-10-15 17:16:11
    RSA签名,Google主要用于APP的来源控制与结算。所谓的结算,也是就是控制了APP只有使用现在机子上登录的Google账户从Google市场曾经下载过该APP的才能够使用,这样也就达到了app销售的目的。   增加RSA签名主要分为...
  • using System; using System.Text; using System.Security.Cryptography; namespace DotNet.Utilities ... /// RSA加密解密及RSA签名和验证 /// public class RSACryption { public RSACryption() {
  • RSA加密解密及RSA签名和验证

    千次阅读 2017-05-24 10:20:17
    2.RSA签名和验证  (1)获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥 (2)获取待签名的Hash码 (3)获取签名的字符串 (4)验证 3.公钥与私钥的理解:  (1)私钥用来进行解密和签名,是给自己用...
  • 近来根据业务需求 在ERP中集成了微信支付,支付宝支付,开发支付宝支付时最大的障碍就是RSA签名,找了很多资料,最终用 下了个libeay32.pas 根据网上资料最终解决了问题       function LoadPrivateKey...
  • C# RSA加密解密及RSA签名和验证

    千次阅读 2017-04-26 10:14:46
    using System; using System.Text; using System.Security.Cryptography; namespace DotNet.Utilities ... /// RSA加密解密及RSA签名和验证 /// public class RSACryption { public RSACryption() {
  • title: 【小程序】RSA签名 type: categories date: 2017-05-27 17:01:15 categories: 小程序tags: [RSA, 签名] 一个适用于微信小程序的RSA签名库。 RSA签名的小程序DEMO:...
  • openssl-RSA签名和验签

    2020-01-14 17:47:14
    openssl-私钥签名(SHA256withRSA)、公钥验签(SHA1withRSA...要用私钥对数据进行RSA签名,用的SHA256withRSA, 然后使用 Base64 封装签名结果,将数据发送到服务器,服务器对数据进行验签。 2、针对服务器返回结果...
  • C#实现RSA签名及认证

    2019-10-06 17:06:22
    C#实现RSA签名及认证 /// <summary> /// 签名 /// </summary> /// <param name="str">需签名的数据</param> /// <returns>签名后的值</returns> public string Sign...
  • 跨平台rsa签名与验签

    千次阅读 2017-01-09 20:46:40
    本文主要讲java和python平台的rsa签名与验签,java使用的是16进制密钥,python使用的是pkcs8编码格式的密钥,其原理其他平台也可以参考。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 66,272
精华内容 26,508
关键字:

rsa签名