Python 和 java的 RSA加密解密

第一次用markdown写博客,看起来不错,用起来感觉一下吧。
言归正传,一个项目的需求是这样的:

服务器端使用python开发,生成一组1024bit的公钥和私钥。通过http把公钥交给android上的app(Java开发的)。App利用公钥加密用户名和密码,再Post到服务器上,服务器利用私钥解密然后验证,验证成功后给App一个Token。

其实就是一个保护用户登录的一个操作。
Python上RSA加密的库挺多的,最开始使用的是rsa,因为比较简单嘛!测试的时候也是用 python模拟App的访问,顺利通过!
然而App开发者反馈,python测试脚本没法移植到java上,因为java的加密解密模块需要更加精细的算法细节指定,否则java加密过的数据python是解不出来的。
当初就是因为rsa模块简单,不需要注重细节才选的,自己又不是专业搞加密解密的。没办法了,只能硬着头皮,捋了一遍RSA的加密原理。网上还是有比较多的讲述比较好的文章,比如RSA算法原理
原理是懂了,但具体到python和java的区别上,还是一头雾水。最终python的RSA模块换成Crypto,因为支持的参数比较多。搜了很多网站讲的都不是很详细,stackflow上有几篇还可以,借鉴了一下,最后测试通过了。还是直接上代码吧。

Java代码

        //下面这行指定了RSA算法的细节,必须更python对应
        private static String RSA_CONFIGURATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
        //这个貌似需要安装指定的provider模块,这里没有使用
    private static String RSA_PROVIDER = "BC";

        //解密 Key:私钥
    public static String decrypt(Key key, String encryptedString){

        try {
            Cipher c = Cipher.getInstance(RSA_CONFIGURATION);
            c.init(Cipher.DECRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
                            PSource.PSpecified.DEFAULT));
            byte[] decodedBytes;
            decodedBytes = c.doFinal(Base64.decode(encryptedString.getBytes("UTF-8")));

            return  new String(decodedBytes, "UTF-8");
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Base64DecodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //加密  Key一般是公钥
public static String encrypt(Key key, String toBeEncryptedString){

        try {
            Cipher c = Cipher.getInstance(RSA_CONFIGURATION);
            c.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
                            PSource.PSpecified.DEFAULT));
            byte[] encodedBytes;
            encodedBytes = c.doFinal(toBeEncryptedString.getBytes("UTF-8"));

            return  Base64.encode(encodedBytes);
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //通过Pem格式的字符串(PKCS8)生成私钥,base64是去掉头和尾的b64编码的字符串
    //Pem格式私钥一般有2种规范:PKCS8和PKCS1.注意java在生成私钥时的不同
    static PrivateKey generatePrivateKeyFromPKCS8(String base64)
    {
        byte[] privateKeyBytes;
        try {
            privateKeyBytes = Base64.decode(base64.getBytes("UTF-8"));
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKeyBytes);
            PrivateKey privateKey = kf.generatePrivate(ks);
            return privateKey;
        } catch (Base64DecodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //通过Pem格式的字符串(PKCS1)生成私钥,base64是去掉头和尾的b64编码的字符串
    static PrivateKey generatePrivateKeyFromPKCS1(String base64)
    {
        byte[] privateKeyBytes;
        try {
            privateKeyBytes = Base64.decode(base64.getBytes("UTF-8"));
            KeyFactory kf = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec  ks = new X509EncodedKeySpec(privateKeyBytes);
            PrivateKey privateKey = kf.generatePrivate(ks);
            return privateKey;
        } catch (Base64DecodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //通过Pem格式的字符串(PKCS1)生成公钥,base64是去掉头和尾的b64编码的字符串
    //Pem格式公钥一般采用PKCS1格式
    static PublicKey generatePublicKeyFromPKCS1(String base64)
    {
        byte[] publicKeyBytes;
        try {
            publicKeyBytes = Base64.decode(base64.getBytes("UTF-8"));
            KeyFactory kf = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec  ks = new X509EncodedKeySpec(publicKeyBytes);
            PublicKey publicKey = kf.generatePublic(ks);
            return publicKey;
        } catch (Base64DecodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //通过modulus和exponent生成公钥
    //参数含义就是RSA算法里的意思
    public static RSAPublicKey getPublicKey(String modulus, String exponent) {  
        try {  
            BigInteger b1 = new BigInteger(modulus);  
            BigInteger b2 = new BigInteger(exponent);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);  
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    } 

Python 代码

from Config import config
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

key = RSA.generate(1024)
pubkey = key.publickey().key
def Decrypt(prikey,data):
                try:
                        cipher = PKCS1_OAEP.new(prikey, hashAlgo=SHA256)
                        return cipher.decrypt(data)
                except:
                        traceback.print_exc()
                        return None

def Encrypt(pubkey,data):
                try:
                        cipher = PKCS1_OAEP.new(pubkey, hashAlgo=SHA256)
                        return cipher.encrypt(data)
                except:
                        traceback.print_exc()
                        return None

总结

  • 主要是对RSA算法不是很熟悉,其中很多术语不懂,导致跟java里的加密模块的函数和类对应不上。
  • RSA算法的细节到现在也是一知半解,但真的没时间去深入学习了。

你可能感兴趣的:(项目经验)