1. Java

RSA & AES encryption

RSA加密算法是一种非对称加密算法。在公开密钥加密电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。
对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
1983年麻省理工学院在美国为RSA算法申请了专利。这个专利2000年9月21日失效。由于该算法在申请专利前就已经被发表了,在世界上大多数其它地区这个专利权不被承认。

代码实现(Java)

package top.sencom.sencq.utils.encrypt;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;


/*
 *
 *由于RSA加密解密速度过慢,所以应当使用RSA来加密传输AES密钥,此后通信双方都使用AES。
 * 
 * */


public class RSAEncrypt {

	
	
	//生成密钥对
	public static void genKeyPair() throws NoSuchAlgorithmException{
		//KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象  
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
		// 初始化密钥对生成器,密钥大小为96-1024位  
		keyPairGen.initialize(1024,new SecureRandom()); 
		// 生成一个密钥对,保存在keyPair中  
		KeyPair keyPair = keyPairGen.generateKeyPair();  
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥    
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
		String publicKeyString = new String(java.util.Base64.getEncoder().encode((publicKey.getEncoded())));  
		// 得到私钥字符串  
		String privateKeyString = new String(java.util.Base64.getEncoder().encode((privateKey.getEncoded())));  
		// 得到公钥字符串  
		System.out.println(publicKeyString);
		System.out.println(privateKeyString);
	
	}
	
	
	//RSA公钥加密 
	public static String encrypt( byte[] str, String publicKey ) throws Exception{
		//base64编码的公钥
		byte[] decoded = java.util.Base64.getDecoder().decode(((publicKey)));
		RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
		//RSA加密
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		String outStr = new String(java.util.Base64.getEncoder().encode(cipher.doFinal(str)));
		//String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
		return outStr;
	}
	
	//RSA私钥解密
	public static String decrypt(byte[] str, String privateKey) throws Exception{
		//BASE64解码加密后的字符串
		byte[] inputByte = java.util.Base64.getDecoder().decode((str));
		//BASE64解码私钥
		byte[] decoded = java.util.Base64.getDecoder().decode((privateKey));  
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));  
		//RSA解密
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		String outStr = new String(cipher.doFinal(inputByte));
		return outStr;
	}
	public static void main(String[] args) throws Exception {
		//生成RSA密钥对
		//RSAEncrypt.genKeyPair();
		String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuIygC5H6eiZOkxJO5sHJXmxZ2hFe5BiarBPuXS4a4maFP7gSi7UUlTXsC06/vkuiREbqJ7ifHjRJopTTEm6bsWCXGqR4gjfNXviaaYwp5mfw2kdB0+5vVNDRWG6hlF1nQCJ2xlirgf0l1BKCv5vVGFfp+2ZxVwR+6T6GOtigwewIDAQAB";
		String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK4jKALkfp6Jk6TEk7mwclebFnaEV7kGJqsE+5dLhriZoU/uBKLtRSVNewLTr++S6JERuonuJ8eNEmilNMSbpuxYJcapHiCN81e+JppjCnmZ/DaR0HT7m9U0NFYbqGUXWdAInbGWKuB/SXUEoK/m9UYV+n7ZnFXBH7pPoY62KDB7AgMBAAECgYEAnKdZ3khKNDsVzFtffePi6TbGnXXvKK8E6EMCRpgWKUlj2fEI0L1cv/MU33UqR/7EI4VsZ5sMxDL/xY4hi2FvZpwF54gJzwia7bunsLSogi2g7qWFoJmfGH+uhoLvxZw/S2mKz67XjJ2bfl6zp/NaeF+QOvVYpY9jA/H3elkj+CECQQD4LzE8Wd0rO5v/Zs8B5wnIgMfL61g+xeCmAUeRTbvMG+J1Aq5M4xhe3EN53a+ReKa13a7zs896cjJLrScC504RAkEAs58DYIHd/GmbpTqCur33Qgnw2CyZ0QPZ7RELPiTVazI5G+Q7xlZr5hXAXy3yEMrN2ohN1dFpYzvRVSscRSO5ywJAU2ZQbk5ocynB306mC6ae9ADKoyz/54BJYJ+XdC2iCRHpxJZVCkNaIi50glRLtl/L7duD+iMXerc7TZDvRhuCcQJAONL8YYKUNK9AUzRAeU1xtI2qiOkLPEmInuv+b4l9ju0TjhRVKLjcZ6zH8BR7+P3/w7vNS/B087TP067Qwbq8owJAMcfHIRsjA5Vp2H0ZY5wUCTMWmTV+OB7xRgd1WmBUiMLmOkvrTe1l9LorGk4e/lhd64q27pTP35V+LV2nP9UOJg==";
		
		String ciphertext = RSAEncrypt.encrypt("你好".getBytes("UTF-8"),publicKey);
		System.out.println(ciphertext);
		String plaintext = RSAEncrypt.decrypt(ciphertext.getBytes("UTF-8"), privateKey);
		System.out.println(plaintext);

	}
}

 

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

代码实现(Java)

package top.sencom.sencq.utils.encrypt;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 * @version V1.0
 * @desc AES 加密
 */
public class AESEncrypt {

    private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法

    /**
     * AES 加密操作
     *
     * @param content 待加密内容
     * @param password 加密密码
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String password) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器

            byte[] result = cipher.doFinal(byteContent);// 加密

            return Base64.encodeBase64String(result);//通过Base64转码返回
        } catch (Exception ex) {
            Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param password
     * @return
     */
    public static String decrypt(String content, String password) {

        try {
            //实例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            //使用密钥初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));

            //执行操作
            byte[] result = cipher.doFinal(Base64.decodeBase64(content));

            return new String(result, "utf-8");
        } catch (Exception ex) {
            Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return null;
    }

    /**
     * 生成加密秘钥
     *
     * @return
     */
    private static SecretKeySpec getSecretKey(final String password) {
        //返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;

        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);

            //AES 要求密钥长度为 128
            kg.init(128, new SecureRandom(password.getBytes()));

            //生成一个密钥
            SecretKey secretKey = kg.generateKey();

            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }

    //测试
    public static void main(String[] args) {
    	
    	int radnum = (int)(1+Math.random()*(10000000-1+1));
    	String key = String.valueOf(radnum);
    	System.out.println(key);
        String s = "hello,你好!";

        System.out.println("s:" + s);

        String s1 = AESEncrypt.encrypt(s, key);
        System.out.println("s1:" + s1);
        
        System.out.println("s2:"+AESEncrypt.decrypt(s1, key));
        

    }

}

 

补充

6.1:对于上述的AES加密在windows环境测试工作正常;但搬到Linux生产环境就会报如下错误

javax.crypto.BadPaddingException:Given final block not properly padded

问题出在这里:

  private static SecretKeySpec getSecretKey(final String password) {
        //返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;

        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);

            //AES 要求密钥长度为 128
            kg.init(128, new SecureRandom(password.getBytes()));

            //生成一个密钥
            SecretKey secretKey = kg.generateKey();

            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }

修改为:

  private static SecretKeySpec getSecretKey(final String password) {
        //返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;

        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
	    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
	    secureRandom.setSeed(secretKey.getBytes());
            //AES 要求密钥长度为 128
            kg.init(128, secureRandom);

            //生成一个密钥
            SecretKey secretKey = kg.generateKey();

            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }

原因:SecureRandom 实现完全随操作系统本身的內部状态,除非调用方在调用 getInstance 方法,然后调用 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。关于SecureRandom类的详细介绍,见 http://yangzb.iteye.com/blog/325264