Java非对称加密

非对称加密算法(RSA)是第一个既可以用于加密数据也可以应用数字签名的算法。RAS算法相对于DES和AES等对称加密算法在速度上要慢很多。使用RSA加密数据时需要使用密钥对,也就是一个公钥,一个私钥。如A、B双方发送数据,A生成密钥对,将公钥发送给B,A将数据用私钥加密后发送给B,而B用A提供的公钥对数据进行解密。如果是B向A发送数据,B用公钥加密数据并发送给A,A使用私钥对数据进行解密。

例:使用RSA生成一对密钥

使用KeyPairGenerator类的generateKeyPair()方法得到KeyPair类,再通过KeyPair类的getPublic()和getPrivate()方法分别生成公钥和密钥,下面代码省略了将密钥保存到文件的方法

public static void createrKeyFile() {

        KeyPairGenerator kpg = null;

        try {

            kpg = KeyPairGenerator.getInstance("RSA");

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        }

  KeyPair kp = kpg.generateKeyPair();//用于生成密钥对

        PublicKey publicKey = kp.getPublic();//得到公钥

        createFile(publicKey.getEncoded(),"D:is/publicKey.dat");

        //得到私钥

        PrivateKey privateKey = kp.getPrivate();

        createFile(privateKey.getEncoded(),"D:is/privateKey.dat");

    }

运行上面该方法,输出如下(RSA的密钥对需要保持一对,它的生成和使用必须配对)

 

 

如服务端使用RSA算法将信息加密再发送到客户端,其中服务端需要分别生成公钥、密文和数字签名并将这3种数据传输给客户端。

RSAServert关键代码 用于生成密钥对(公钥和私钥)、数字签名,并将生成的数据以文件形式保存下来,客户端得到密文、公钥和数字签名才能对密文进行解密。

//生成密钥对方法

public void generateKey() {

        KeyPairGenerator kpg = null;

        try {

//KeyPairGenerator类用于生成密钥对,基于RSA算法生成对象

            kpg = KeyPairGenerator.getInstance("RSA");

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        }

        KeyPair kp = kpg.generateKeyPair();

        //得到 公钥

        PublicKey publicKey = kp.getPublic();

        writeFile(publicKey.getEncoded(), "D:/encryptedFile/publicKey.dat");//将数据以文件的形式保存下来

        PrivateKey privateKey = kp.getPrivate();// 得到私钥

        writeFile(privateKey.getEncoded(), "D:/encryptedFile/PrivateKey.dat");

    }

 

下面方法使用私钥对数据进行加密,先获取到私钥对象,使用私钥对数据进行加密,将加密后的数据以文件形式保存下来。(抛异常应该以try catch语句抛出异常,这篇幅有限所以使用throws Execption统一将异常抛给调用处理)

public void privateKeyEncryption (byte[] data) throws Exception {

        // 读取私钥数据(byte数组形式返回)

        byte[] by = readFile("D:/encryptedFile/PrivateKey.dat");

//使用得到byte数组构造PKCS8EncodedKeySpec对象

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(by);

        KeyFactory keyFactory = null;

        Key privateKey = null;

        keyFactory = KeyFactory.getInstance("RSA");

    //使用KeyFactory类的generatePrivate()方法获取私钥对象 pkcs8KeySpec 表示根据提供的密钥材料生成私钥对象

        privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密 Cipher.ENCRYPT_MODE表示加密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        writeFile(cipher.doFinal(data), "ServerData.dat");

       

    }

 

RSA生成数字签名,需要使用私钥和密文生成签名。其中使用Signature类的sign()方法生成数字签名

//根据私钥生成数字签名

public void GenerateDigitalSignature() throws Exception {

        //获取私钥

        byte[] privateKey = readFile("D:/encryptedFile/PrivateKey.dat");

        byte[] serverData = readFile("ServerData.dat");//密文

        // 构造PKCS8EncodedKeySpec对象

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);

        KeyFactory keyFactory = null; //声明

        PrivateKey priKey = null;

        keyFactory = KeyFactory.getInstance("RSA");

        priKey = keyFactory.generatePrivate(pkcs8KeySpec); //得到私钥

        //指定证书算法为MD5withRSA

        Signature signature = Signature.getInstance("MD5withRSA");

        signature.initSign(priKey);

        signature.update(serverData);

        //以文件形式保存数字签名

        writeFile(signature.sign(), "D:/encryptedFile/SignData.dat");

    }

编写测试方法,分别实例化RSAServer类和RSAClient类,调用方法生成密钥对,对发送的数据进行加密后,再调用方法生成数字签名,生成数字签名后验证数字签名的有效性,验证有效的话才可以解密。

@Test

    public void test() {

        String msg = "这是服务端加密后发送的数据";

//实例化当前类

        RSAServer server = new RSAServer();

        server.generateKey();// 调用方法生成密钥对

        server.privateKeyEncryption(msg.getBytes());// 加密发送数据

        server.GenerateDigitalSignature();// 生成数字签名

        RSAClient client = new RSAClient();// 实例化客户端类

        byte[]  by =null; //声明数组

//调用RSAClient类的方法校对数字签名是否有效

        if(client.VerifyDigitalSignature ()){

            by= client.decryptByPublicKey();

        }

        System.out.println("服务端加密发送的数据:"+msg);

        System.out.println("客户端解密的数据:"+new String (by)); 

}

 

 

 

RSAClient类关键代码 该类用于解密RSAServert类加密的数据

下面方法用于对数字签名的验证,因为RSAServert类的方法生成了数字签名,所以需要RSAClient类需要编写对数字签名的验证方法,如RSAServert类不生成数字签名,则RSAClient也不需要验证数字签名。

//验证数字签名

public boolean VerifyDigitalSignature() throws Exception {

        byte[] data =readFile("ServerData.dat");//读取RSAServert加密的密文文件

        byte[] publicKey = readFile("D:/encryptedFile/publicKey.dat");//公钥

//读取RSAServer生成数字签名文件

        byte[] sign = readFile("D:/encryptedFile/SignData.dat");

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);

        KeyFactory keyFactory = null;

        PublicKey pubKey = null;

        keyFactory = KeyFactory.getInstance("RSA");

        pubKey = keyFactory.generatePublic(keySpec); //得到公钥对象

        Signature signature = Signature.getInstance("MD5withRSA");

        signature.initVerify(pubKey); /*初始化此用于验证的公钥对象,如果密钥无效,则会抛出invalidkeyException异常*/

        signature.update(data); //使用指定的 byte 数组更新要签名或验证的数据

 return signature.verify(sign); //验证传入的签名有效性,有效返回true,反之false

    }

decryptByPublicKey方法需要注意的是X509EncodedKeySpec用于构建公钥规范,PKCS8EncodedKeySpec用于构造私钥规范

//使用公钥对数据进行解密

public byte[] decryptByPublicKey() {

        byte[] data = readFile("ServerData.dat");

        byte[] key = readFile("D:/encryptedFile/publicKey.dat");

//构建公钥规范

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);

        KeyFactory keyFactory = null;

        Key publicKey = null;

        keyFactory = KeyFactory.getInstance("RSA");

        publicKey = keyFactory.generatePublic(x509KeySpec); // 取得公钥

        //根据算法名称返回指定转换的Cipher对象

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

// 初始化 Cipher.DECRYPT_MODE表示解密

        cipher.init(Cipher.DECRYPT_MODE, publicKey);

         //完成解密返回包含缓冲区

         return cipher.doFinal(data);

    }

 

 

 

 

下面这里RSAClient类的加密方法跟RSAServert类的加密方法都是大同小异的,读取公钥,构建公钥规范,使用KeyFactory类的generatePublic()方法生成公钥对象(KeyFactory类最常用的操作就是通过密钥规范生成相关密钥对象),然后就是加密操作了。

//使用公钥加密数据

public void encryptOfClient(byte[] data) {

        byte[] key = readFile("D:/encryptedFile/publicKey.dat");

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);

        KeyFactory keyFactory = null;

        Key publicKey = null;

        keyFactory = KeyFactory.getInstance("RSA");

        publicKey = keyFactory.generatePublic(x509KeySpec);

        // 下面是加密操作

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        writeFile(cipher.doFinal(data), "ClientData.dat");//保存密文

    }

 编写测试方法,分别实例化相关类,调用方法加密、解密,然后输出数据

    @Test

    public void test() {

        //实例化

        RSAClient client = new RSAClient();

        RSAServer server = new RSAServer();

        String msg = "客户端加密后发送的信息"

        client.encryptOfClient(msg.getBytes());//调用方法对数据进行加密

        byte [] data = server.decryptByPrivateKey();//调用RSAServert的方法解密

        System.out.println("客户端加密发送的数据:"+msg);

        System.out.println("服务端解密后数据:"+new String (data));

    }

       

编写riteFile()方法将byte[]的数据写入文件

public void writeFile(byte[] data, String fileName) {

    //省略代码

    }

编写readFile()方法读取文件并以byte[]返回数据

public byte[] readFile(String fileName) {

        //省略代码

}

 

运行RSAClient类的Test方法,客户端将数据加密后发送到服务端,效果如下

运行RSAServert类的Test方法,服务端加密数据并发送到客户端,效果如下

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值