Introduction to encryption


This paper uses symmetric encryption algorithm DES and asymmetric encryption algorithm RSA to do data transmission encryption. Symmetric encryption DES: Symmetric encryption uses a single-key password to encrypt and decrypt information using the same secret key. This method is also called single-key encryption. Symmetry means that encryption and decryption use the same secret key! Common symmetric encryption algorithms include DES, IDEA, RC2, RC4, SKIPJACK, RC5, and AES. Different from symmetric encryption algorithms, asymmetric encryption algorithms require two keys: a publickey and a privatekey. The public key and private key are a pair. If the public key is used to encrypt data, only the corresponding private key can be used to decrypt data. If data is encrypted with a private key, it can only be decrypted with the corresponding public key. Because encryption and decryption use two different keys, the algorithm is called asymmetric encryption. RSA public key encryption algorithm was developed in 1977 by Ron Rivest, Adi Shamirh, and Lena Leman (MIT). RSA takes its name from the names that developed all three. RSA is the most influential public key encryption algorithm at present. It can resist all cryptographic attacks known to date and has been recommended by ISO as the public key data encryption standard. The RSA algorithm was based on a very simple number theory fact: it was easy to multiply two large prime numbers, but at the time it was extremely difficult to factor their product, so the product could be exposed as an encryption key.


2. RSA key generation


RSA keys are generated using The OpenSSL protocol. In this document, only public and private keys are generated. You can use CA certificates to generate keys if necessary

1. OpenSSL installation

Slproweb.com/products/Wi… Select 32-bit and 64-bit for download and installation

2. Open up your workspace

Open bin in the OpenSSL installation directory and run openSSL. exe to go to the OpenSSL workspace

3. Key generation

Private key generation (generated in bin directory)

genrsa -out rsa_private_key.pem 1024

Openssl randomly generates a private key with an encryption length of 1024 bits. Encryption length refers to the theoretical maximum allowable length of “encrypted message”, that is, the length limit of plaintext. As this parameter increases (say 2048), the allowed plaintext length increases, but computational complexity increases dramatically. The recommended length is 1024 bits (128 bytes). The private key used by JAVA needs to be PKCS#8 encoded. PHP programs do not need the current private key format.

pkcs8 -topk8 -inform PEM -in pkcs8_rsa_private_key.pem -outform PEM -nocrypt

② Public key generation

rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

Thus, the preparatory work for RSA+DES is complete



Three, Android terminal configuration

This paper focuses on encrypted data transmission process, adopt encryption Json string to complete the whole process of encryption, therefore, need to unify transmission parameters for “data = * * * * * * * * & sign =” * * * * * * * * * * * * * * * * * * * “format, if you have any other requirements please change on its own. As the network framework of this project adopts Retrofit+OkHttp implementation, the encryption process of parameters is realized by OkHttp interceptor

public class EncryptionInterceptor implements Interceptor { private Context mContext; public EncryptionInterceptor(Context context) { this.mContext = context; } @Override public Response intercept(@NonNull Chain chain) throws IOException { Request request = chain.request(); RequestBody oldBody = request.body(); Buffer buffer = new Buffer(); if (oldBody ! = null) { oldBody.writeTo(buffer); } String strOldBody = buffer.readUtf8(); Map<String, String> map = new HashMap<>(); String dataByte = URLDecoder.decode(strOldBody.substring(5), "utf-8"); Byte [] desKey = descoder.initkey (); Byte [] encrypt = DESCoder. Encrypt (databyt.getBytes (), desKey); byte[] encrypt = DESCoder. map.put("data", parseByte2HexStr(encrypt)); //RSA encrypt RSAEncrypt RSAEncrypt = new RSAEncrypt(); InputStream inputStream = mContext.getResources().getAssets().open("rsa_public_key.pem"); //rsa sets the public key rsaencrypt. loadPublicKey(inputStream); Byte [] rsaData = rsaencrypt. encrypt(rsaencrypt.getPublicKey (), desKey); // Rsa encryption DES key byte[] rsaData = rsaencrypt. encrypt(rsaencrypt.getPublicKey (), desKey); map.put("sign", parseByte2HexStr(rsaData)); } catch (Exception e) { e.printStackTrace(); } FormBody body = new FormBody.Builder().add("data", map.get("data")).add("sign", map.get("sign")).build(); request = request.newBuilder().header("Content-Type", body.contentType().type()).header("Content-Length", String.valueOf(body.contentLength())).method(request.method(), body).build(); return chain.proceed(request); } @since v1.0 */ private static String parseByte2HexStr(byte buf[]) {StringBuilder sb = new StringBuilder(); for (byte aBuf : buf) { String hex = Integer.toHexString(aBuf & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /** * public static String ** @paramVALUES Parameter map object * @return Parameter list String */ Public static String getParamsOrderByKey(Map<String, String> paramValues) { String params = ""; List<String> paramNames = new ArrayList<>(paramValues.size()); paramNames.addAll(paramValues.keySet()); Collections.sort(paramNames); for (String paramName : paramNames) { if (params.equals("")) { params += paramName + "=" + paramValues.get(paramName); } else { params += "&" + paramName + "=" + paramValues.get(paramName); } } return params; } /** * convert hexadecimal to binary ** @since v1.0 */ public byte[] parseHexStr2Byte(String hexStr) {if (hexstr.length () < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; }}Copy the code

Add an OkHttp interceptor

new OkHttpClient.Builder()
                .addInterceptor(new EncryptionInterceptor(this))
                .build();
Copy the code

RSA tool class implementation

public class RSAEncrypt {
public static final String DEFAULT_PUBLIC_KEY =
        "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1Qcf1zVOuhseFxvo6+FnVvEPs" + "\r" + "Uvczg6oX+HjMNksiiDWcNkbPHfznaPDtgoBY2xF0R8HGHbrT53LNvkj7UMcI48tq" + "\r" + "K+B4YdJHe9SgJVDCCiceLLGtf/ev206qJ/XgKgrLFD+vMmjIB8gQCkZvy/dxhEf1" + "\r" + "aAmoz5tdJhOVdxT7QwIDAQAB" + "\r";

public static final String DEFAULT_PRIVATE_KEY =
        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALVBx/XNU66Gx4XG" + "\r" +
                "+jr4WdW8Q+xS9zODqhf4eMw2SyKINZw2Rs8d/Odo8O2CgFjbEXRHwcYdutPncs2+" + "\r" +
                "SPtQxwjjy2or4Hhh0kd71KAlUMIKJx4ssa1/96/bTqon9eAqCssUP68yaMgHyBAK" + "\r" +
                "Rm/L93GER/VoCajPm10mE5V3FPtDAgMBAAECgYAf1hEAHHNhSS0MUzmqV+q3ftzT" + "\r" +
                "SnM+6hZbJXpaLAMgapo3+NSRFmxQXP9MSEqw0LGNIfloCdrB03o3pv98nOCIZCh7" + "\r" +
                "PHsU2GhxJ04Qro+wKhK358326KNXCjjqVIBG0xMbJxVhjM2/jjfocxFpe5iD7h53" + "\r" +
                "c+GvDgUVduAYO4I1GQJBAO21n2aIzQV3mScS1O8BRV+9CmHaDbVHqBetRoB3kJ2U" + "\r" +
                "piflKTNofwWmTA5A8sKt8WcOz7LsB2SWcp9jNvatxA8CQQDDNCmfo6eix9e5f11K" + "\r" +
                "Rf8sRiN7XGDzlKkZlmQAN0UtXdTP4AN9cuZrwnntWKysXr/zLntYLGYn9rdrohbD" + "\r" +
                "9RGNAkBOEsog7iuQcSCfQcMoIN29PSSs0OaRtNBTvniadyrLZuhP0CeBGAAoRd9T" + "\r" +
                "CyfwoxrXg3jaRkWDVxqcmQSTbq0nAkB8flcRhilSqsuNdYpE5VFxpiXY9jirAKO8" + "\r" +
                "Our6LEXFQjOIhCEVr+L+1OA4HDa8FA2thXaK7H4WfMXMMmr8fN69AkEAuR0YU9My" + "\r" +
                "snzWLDWYR5sNp90PhyDSL/HTZHBnebD+JlAYwoYRFYt+tXw0/PEmV2B3thYGPeiZ" + "\r" +
                "kHKd/TeLIVbxGg==" + "\r";

/**
 * 私钥
 */
private RSAPrivateKey privateKey;

/**
 * 公钥
 */
private RSAPublicKey publicKey;

/**
 * 字节数据转字符串专用集合
 */
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};


/**
 * 获取私钥
 *
 * @return 当前的私钥对象
 */
public RSAPrivateKey getPrivateKey() {
    return privateKey;
}

/**
 * 获取公钥
 *
 * @return 当前的公钥对象
 */
public RSAPublicKey getPublicKey() {
    return publicKey;
}

/**
 * 随机生成密钥对
 */
public void genKeyPair() {
    KeyPairGenerator keyPairGen = null;
    try {
        keyPairGen = KeyPairGenerator.getInstance("RSA");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    keyPairGen.initialize(1024, new SecureRandom());
    KeyPair keyPair = keyPairGen.generateKeyPair();
    this.privateKey = (RSAPrivateKey) keyPair.getPrivate();
    this.publicKey = (RSAPublicKey) keyPair.getPublic();
}

/**
 * 从文件中输入流中加载公钥
 *
 * @param in 公钥输入流
 * @throws Exception 加载公钥时产生的异常
 */
public void loadPublicKey(InputStream in) throws Exception {
    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String readLine = null;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            if (readLine.charAt(0) == '-') {
                continue;
            } else {
                sb.append(readLine);
                sb.append('\r');
            }
        }
        loadPublicKey(sb.toString());
    } catch (IOException e) {
        throw new Exception("公钥数据流读取错误");
    } catch (NullPointerException e) {
        throw new Exception("公钥输入流为空");
    }
}


/**
 * 从字符串中加载公钥
 *
 * @param publicKeyStr 公钥数据字符串
 * @throws Exception 加载公钥时产生的异常
 */
public void loadPublicKey(String publicKeyStr) throws Exception {
    try {
    // byte[] buffer = Base64.decode(publicKeyStr.getBytes(), Base64.DEFAULT);
        BASE64Decoder base64Decoder= new BASE64Decoder();
        byte[] buffer= base64Decoder.decodeBuffer(publicKeyStr);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
        this.publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("无此算法");
    } catch (InvalidKeySpecException e) {
        throw new Exception("公钥非法");
    } catch (NullPointerException e) {
        throw new Exception("公钥数据为空");
    }
}

/**
 * 从文件中加载私钥
 *
 * @return 是否成功
 * @throws Exception
 */
public void loadPrivateKey(InputStream in) throws Exception {
    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String readLine = null;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            if (readLine.charAt(0) == '-') {
                continue;
            } else {
                sb.append(readLine);
                sb.append('\r');
            }
        }
        loadPrivateKey(sb.toString());
    } catch (IOException e) {
        throw new Exception("私钥数据读取错误");
    } catch (NullPointerException e) {
        throw new Exception("私钥输入流为空");
    }
}

public void loadPrivateKey(String privateKeyStr) throws Exception {
    try {
        //byte[] buffer = Base64.encode(privateKeyStr.getBytes(), Base64.DEFAULT);
        BASE64Decoder base64Decoder= new BASE64Decoder();
        byte[] buffer= base64Decoder.decodeBuffer(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        this.privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("无此算法");
    } catch (InvalidKeySpecException e) {
        throw new Exception("私钥非法");
    } catch (NullPointerException e) {
        throw new Exception("私钥数据为空");
    }
}

/**
 * 加密过程
 *
 * @param publicKey     公钥
 * @param plainTextData 明文数据
 * @return
 * @throws Exception 加密过程中的异常信息
 */
public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
    if (publicKey == null) {
        throw new Exception("加密公钥为空, 请设置");
    }
    Cipher cipher = null;
    try {
     
        cipher = Cipher.getInstance("RSA");
        //Android端无需添加此加密提供者,已默认实现
        //cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plainTextData);
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("无此加密算法");
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
        return null;
    } catch (InvalidKeyException e) {
        throw new Exception("加密公钥非法,请检查");
    } catch (IllegalBlockSizeException e) {
        throw new Exception("明文长度非法");
    } catch (BadPaddingException e) {
        throw new Exception("明文数据已损坏");
    }
}

/**
 * 解密过程
 *
 * @param privateKey 私钥
 * @param cipherData 密文数据
 * @return 明文
 * @throws Exception 解密过程中的异常信息
 */
public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
    if (privateKey == null) {
        throw new Exception("解密私钥为空, 请设置");
    }
    Cipher cipher = null;
    try {
        cipher = Cipher.getInstance("RSA");
        //Android端无需添加此加密提供者,已默认实现
        //cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] output = cipher.doFinal(cipherData);
        return output;
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("无此解密算法");
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
        return null;
    } catch (InvalidKeyException e) {
        throw new Exception("解密私钥非法,请检查");
    } catch (IllegalBlockSizeException e) {
        throw new Exception("密文长度非法");
    } catch (BadPaddingException e) {
        throw new Exception("密文数据已损坏");
    }
}


/**
 * 字节数据转十六进制字符串
 *
 * @param data 输入数据
 * @return 十六进制内容
 */
public static String byteArrayToString(byte[] data) {
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < data.length; i++) {
        //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移  
        stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
        //取出字节的低四位 作为索引得到相应的十六进制标识符  
        stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
        if (i < data.length - 1) {
            stringBuilder.append(' ');
        }
    }
    return stringBuilder.toString();
}


public static void main(String[] args) {
    RSAEncrypt rsaEncrypt = new RSAEncrypt();

    //加载公钥
    try {
        rsaEncrypt.loadPublicKey(RSAEncrypt.DEFAULT_PUBLIC_KEY);
        System.out.println("加载公钥成功");
    } catch (Exception e) {
        System.err.println(e.getMessage());
        System.err.println("加载公钥失败");
    }
    /*try {
        rsaEncrypt.loadPublicKey(RSAEncrypt.DEFAULT_PUBLIC_KEY);
        System.out.println("加载公钥成功");
    } catch (Exception e) {
        System.err.println(e.getMessage());
        System.err.println("加载公钥失败");
    }
    //加载私钥
    try {
        rsaEncrypt.loadPrivateKey(RSAEncrypt.DEFAULT_PRIVATE_KEY);
        System.out.println("加载私钥成功");
    } catch (Exception e) {
        System.err.println(e.getMessage());
        System.err.println("加载私钥失败");
    }
    try {
        SecureRandom sr = new SecureRandom();
        KeyGenerator kg = KeyGenerator.getInstance("DES");
        kg.init(56, sr);
        SecretKey generateKey = kg.generateKey();
        String encodeHexString = Hex.toHexString(generateKey.getEncoded());
        System.out.println(encodeHexString);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    //测试字符串
    String encryptStr= "Test String chaijunkun";

    try {
        //加密
        long encryptStart = System.currentTimeMillis();
        byte[] cipher = rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(), encryptStr.getBytes());
        long encryptEnd = System.currentTimeMillis();
        System.out.println("密文长度:"+ cipher.length);
        System.out.println(RSAEncrypt.byteArrayToString(cipher));
        System.out.println("加密时间"+ (encryptEnd-encryptStart));

        //解密
        long decryptStart = System.currentTimeMillis();
        byte[] plainText = rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(), cipher);
        long decryptEnd = System.currentTimeMillis();
        System.out.println("明文长度:"+ plainText.length);
        System.out.println(RSAEncrypt.byteArrayToString(plainText));
        System.out.println("解密时间"+ (decryptEnd-decryptStart));

        System.out.println(new String(plainText));
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }*/ 
        }
}  
Copy the code

DES utility class implementation

Bouncy Castle supports 64 bit keys. Bouncy Castle supports 64 bit keys. Bouncy Castle supports 64 bit keys = "DES"; Public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; /** * Conversion key * @param key Binary key * @Return key key * @throws Exception */ Private static key toKey(byte[] key) throws Exception{// Instantiate DES key material DESKeySpec DKS = new DESKeySpec(key); / / instantiate the key factory SecretKeyFactory keyFactory = SecretKeyFactory. GetInstance (KEY_ALGORITHM); / / production key SecretKey SecretKey. = keyFactory generateSecret (DKS); return secretKey; } /** * Decrypt * @param data Data to be decrypted * @param key key * @return byte[] Decrypt data * @throws Exception */ public static byte[] Decrypt (byte[] data,byte[] key) throws Exception{// Restore key k = toKey(key); // Instantiate Cipher Cipher = cipher.getinstance (CIPHER_ALGORITHM); // Initialize to cipher.init(cipher.decrypt_mode, k); Return cipher.doFinal(data); } /** * Encrypt * @param data Data to be encrypted * @param key key * @return byte[] Encrypt data * @throws Exception */ public static byte[] Encrypt (byte[] data,byte[] key) throws Exception{// Restore key k = toKey(key); encrypt(byte[] key) throws Exception{// Restore key k = toKey(key); Cipher = cipher.getInstance (CIPHER_ALGORITHM,new BouncyCastleProvider()); // Instantiate Cipher Cipher = cipher.getInstance (CIPHER_ALGORITHM,new BouncyCastleProvider()); Cipher.init (cipher.encrypt_mode,k); // Initialize to cipher.init(cipher.encrypt_mode,k); Return cipher.doFinal(data); Bouncy Castle supports 64-bit keys * @return byte[] Binary keys * @throws Exception */ public static Byte [] initKey() throws Exception{/* * instantiate KeyGenerator * to use 64-bit keys replace * keygenerator.getinstance (KEY_ALGORITHM) in the following code. * Replace with * keygenerator. getInstance(KEY_ALGORITHM, "BC"); */ KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM,new BouncyCastleProvider()); kg.init(64); SecretKey = kg.generateKey(); Return secretkey.getencoded (); }}Copy the code

4. JavaWeb configuration

The Web back end simply adds the following code to the Controller, accepts data and sign from the server, and converts the received Json string into an entity class

Public <T> T convertJson(String data, String data, String data); String sign,Class<T> clazz) { System.out.println(data); System.out.println(sign); T tClass = null; Try {// RSA encrypt RSAEncrypt RSAEncrypt = new RSAEncrypt(); InputStream in = new FileInputStream(new File("C:\\ openSSL-win64 \\bin\\ pkCS8_rsa_private_key.pem ")); rsaEncrypt.loadPrivateKey(in); Byte [] keyBytes = parseHexStr2Byte(sign); // Obtain the RSA encrypted key data and convert the hexadecimal sign into byte[] (the client converts byte[] to hexadecimal for data upload). Byte [] rsaKey = rsaencrypt.decrypt (rsaencrypt.getPrivateKey (), keyBytes); byte[] rsaKey = rsaencrypt.decrypt (rsaencrypt.getPrivateKey (), keyBytes); Byte [] desData = DESCoder. Decrypt (parseHexStr2Byte(data), rsaKey); System.out.println(Arrays.toString(desData)); System.out.println(new String(desData)); tClass = JSON.parseObject(new String(desData), clazz); } catch (Exception e) { e.printStackTrace(); } return tClass; }Copy the code

Fifth, note

Star Github this article is only for learning and communication, reprint must indicate the source