Java Encryption Algorithms - Summary of Encryption Algorithms

Java Encryption Algorithms - Summary of Encryption Algorithms

Such as the basic one-way encryption algorithm:

  • Strictly speaking, BASE64 is an encoding format, not an encryption algorithm

  • MD5 (Message Digest algorithm 5, information digest algorithm)

  • SHA (Secure Hash Algorithm, secure hash algorithm)

  • HMAC (Hash Message Authentication Code, hash message authentication code)

    Complex symmetric encryption (DES, PBE), asymmetric encryption algorithm:

  • DES (Data Encryption Standard, data encryption algorithm)

  • PBE (Password-based encryption, based on password authentication)

  • RSA (the algorithm is named after its inventors: Ron Rivest, AdiShamir and Leonard Adleman)

  • DH (Diffie-Hellman algorithm, key consensus protocol)

  • DSA (Digital Signature Algorithm, digital signature)

  • ECC (Elliptic Curves Cryptography, Elliptic Curve Cryptography)

    This article briefly introduces several methods of BASE64 , MD5 , SHA , and HMAC . The three encryption algorithms
    MD5 , SHA , and HMAC can be described as non-reversible encryption, that is, an encryption method that cannot be decrypted. We usually just use them as the basis for encryption. The encryption of the above three types alone is not reliable.

BASE64
According to the definition of RFC2045, Base64 is defined as: Base64 content transfer encoding is designed to describe any sequence of 8-bit bytes as a form that is not easy to be directly recognized by humans. (The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
Commonly used in email, http encryption, intercepting http information, you will find the username and password fields for login operations Encrypted by BASE64.

Various Java encryption algorithms

Through the java code to achieve as follows:

/**
     * BASE64解密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
    
    
        return (new BASE64Decoder()).decodeBuffer(key);
    }
 
    /**
     * BASE64加密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
    
    
        return (new BASE64Encoder()).encodeBuffer(key);
    }

There are mainly two classes of BASE64Encoder and BASE64Decoder. We only need to know how to use them. In addition, the number of bytes generated after BASE encryption is a multiple of 8, if the number of bytes is not enough, it will be filled with **=** symbols.

MD5
MD5 – message-digest algorithm 5 (information-digest algorithm) abbreviation, widely used in encryption and decryption technology, often used in file verification. check? No matter how big the file is, a unique MD5 value can be generated after MD5. For example, the current ISO checksums are all MD5 checksums. how to use? Of course, the MD5 value is generated after passing the ISO through MD5. Generally, friends who download linux-ISO have seen MD5 strings next to the download link. It is used to verify whether the files are consistent.

Various Java encryption algorithms

Through the java code to achieve as follows:

/**
     * MD5加密
     * 
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) throws Exception {
    
    
 
        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
 
        return md5.digest();
 
    }

Usually we don't use the above MD5 encryption directly. Usually, the byte array generated by MD5 is given to BASE64 and then encrypted to obtain the corresponding string.

SHA
SHA (Secure Hash Algorithm, secure hash algorithm), digital signature and other important tools in cryptography applications are widely used in e-commerce and other information security fields. Although both SHA and MD5 have been cracked by the collision method, SHA is still a recognized security encryption algorithm, which is more secure than MD5.

Various Java encryption algorithms

Through the java code to achieve as follows:

/**
     * SHA加密
     * 
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data) throws Exception {
    
    
 
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);
 
        return sha.digest();
 
    }
}

HMAC
HMAC (Hash Message Authentication Code, Hash Message Authentication Code, an authentication protocol based on the key-based Hash algorithm. The principle of message authentication code to achieve authentication is to use a public function and a key to generate a fixed-length value as an authentication identifier, and use This identity authenticates the integrity of the message.Use a key to generate a small data block of fixed size, that is, MAC, and add it to the message, and then transmit it.The receiver uses the key shared with the sender for authentication and so on.

Various Java encryption algorithms

Through the java code to achieve as follows:

/**
     * 初始化HMAC密钥
     * 
     * @return
     * @throws Exception
     */
    public static String initMacKey() throws Exception {
    
    
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
 
        SecretKey secretKey = keyGenerator.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }
 
    /**
     * HMAC加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
    
    
 
        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
 
        return mac.doFinal(data);
 
    }

Given a complete class, as follows:

import java.security.MessageDigest;
 
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
 
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
/**
 * 基础加密组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class Coder {
    
    
    public static final String KEY_SHA = "SHA";
    public static final String KEY_MD5 = "MD5";
 
    /**
     * MAC算法可选以下多种算法
     * 
     * <pre>
     * HmacMD5 
     * HmacSHA1 
     * HmacSHA256 
     * HmacSHA384 
     * HmacSHA512
     * </pre>
     */
    public static final String KEY_MAC = "HmacMD5";
 
    /**
     * BASE64解密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
    
    
        return (new BASE64Decoder()).decodeBuffer(key);
    }
 
    /**
     * BASE64加密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
    
    
        return (new BASE64Encoder()).encodeBuffer(key);
    }
 
    /**
     * MD5加密
     * 
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) throws Exception {
    
    
 
        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
 
        return md5.digest();
 
    }
 
    /**
     * SHA加密
     * 
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data) throws Exception {
    
    
 
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);
 
        return sha.digest();
 
    }
 
    /**
     * 初始化HMAC密钥
     * 
     * @return
     * @throws Exception
     */
    public static String initMacKey() throws Exception {
    
    
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
 
        SecretKey secretKey = keyGenerator.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }
 
    /**
     * HMAC加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
    
    
 
        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
 
        return mac.doFinal(data);
 
    }
}

Give another test class:

import static org.junit.Assert.*;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CoderTest {
    
    
 
    @Test
    public void test() throws Exception {
    
    
        String inputStr = "简单加密";
        System.err.println("原文:\n" + inputStr);
 
        byte[] inputData = inputStr.getBytes();
        String code = Coder.encryptBASE64(inputData);
 
        System.err.println("BASE64加密后:\n" + code);
 
        byte[] output = Coder.decryptBASE64(code);
 
        String outputStr = new String(output);
 
        System.err.println("BASE64解密后:\n" + outputStr);
 
        // 验证BASE64加密解密一致性
        assertEquals(inputStr, outputStr);
 
        // 验证MD5对于同一内容加密是否一致
        assertArrayEquals(Coder.encryptMD5(inputData), Coder
                .encryptMD5(inputData));
 
        // 验证SHA对于同一内容加密是否一致
        assertArrayEquals(Coder.encryptSHA(inputData), Coder
                .encryptSHA(inputData));
 
        String key = Coder.initMacKey();
        System.err.println("Mac密钥:\n" + key);
 
        // 验证HMAC对于同一内容,同一密钥加密是否一致
        assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC(
                inputData, key));
 
        BigInteger md5 = new BigInteger(Coder.encryptMD5(inputData));
        System.err.println("MD5:\n" + md5.toString(16));
 
        BigInteger sha = new BigInteger(Coder.encryptSHA(inputData));
        System.err.println("SHA:\n" + sha.toString(32));
 
        BigInteger mac = new BigInteger(Coder.encryptHMAC(inputData, inputStr));
        System.err.println("HMAC:\n" + mac.toString(16));
    }
}

Console output:

原文:
简单加密
BASE64加密后:
566A5Y2V5Yqg5a+G

BASE64解密后:
简单加密
Mac密钥:
uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke
pBIpkd7QHg==

MD5:
-550b4d90349ad4629462113e7934de56
SHA:
91k9vo7p400cjkgfhjh0ia9qthsjagfn
HMAC:
2287d192387e95694bdbba2fa941009a

Note
When compiling, you may see the following prompt:

quote

WARNING: sun.misc.BASE64Decoder is a Sun proprietary API and may be removed in a future release

import sun.misc.BASE64Decoder;
^
WARNING: sun.misc.BASE64Encoder is a Sun proprietary API and may be removed in a future release

import sun.misc.BASE64Encoder;
^

BASE64Encoder and BASE64Decoder are unofficial JDK implementation classes. Although it can be found and used in the JDK, it cannot be found in the API. The classes in packages beginning with sun and com.sun in JRE are undocumented. They belong to the base of java and javax class libraries, and most of the implementations are related to the underlying platform. Generally speaking, they are not recommended.

The encryption and decryption of BASE64 are two-way, and the reverse solution can be obtained.
MD5, SHA, and HMAC are one-way encryption. Any encrypted data will only generate a unique encrypted string, which is usually used to verify whether the data has been modified during transmission. Among them, the HMAC algorithm has a key, which enhances the security during data transmission and strengthens the uncontrollable factors outside the algorithm.
The purpose of one-way encryption is mainly to verify whether the data has been modified during transmission.

Next we introduce the symmetric encryption algorithm, the most commonly used one is the DES data encryption algorithm.
DES
DES-Data Encryption Standard, the data encryption algorithm. It was successfully researched and published by IBM in 1975. There are three entry parameters of the DES algorithm: Key, Data, and Mode. Among them, Key is 8 bytes and 64 bits in total, which is the working key of the DES algorithm; Data is also 8 bytes and 64 bits, which is the data to be encrypted or decrypted; Mode is the working mode of DES, and there are two types: Encrypt or decrypt.
The DES algorithm changes a 64-bit plaintext input block into a 64-bit ciphertext output block, and the key it uses is also 64 bits.

Through the java code to achieve as follows: Coder class see

import java.security.Key;
import java.security.SecureRandom;
 
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
 
 
/**
 * DES安全编码组件
 * 
 * <pre>
 * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
 * DES                  key size must be equal to 56
 * DESede(TripleDES)     key size must be equal to 112 or 168
 * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
 * Blowfish          key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
 * RC2                  key size must be between 40 and 1024 bits
 * RC4(ARCFOUR)      key size must be between 40 and 1024 bits
 * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
 * </pre>
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class DESCoder extends Coder {
    
    
    /**
     * ALGORITHM 算法 <br>
     * 可替换为以下任意一种算法,同时key值的size相应改变。
     * 
     * <pre>
     * DES                  key size must be equal to 56
     * DESede(TripleDES)     key size must be equal to 112 or 168
     * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
     * Blowfish          key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
     * RC2                  key size must be between 40 and 1024 bits
     * RC4(ARCFOUR)      key size must be between 40 and 1024 bits
     * </pre>
     * 
     * 在Key toKey(byte[] key)方法中使用下述代码
     * <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换
     * <code>
     * DESKeySpec dks = new DESKeySpec(key);
     * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
     * SecretKey secretKey = keyFactory.generateSecret(dks);
     * </code>
     */
    public static final String ALGORITHM = "DES";
 
    /**
     * 转换密钥<br>
     * 
     * @param key
     * @return
     * @throws Exception
     */
    private static Key toKey(byte[] key) throws Exception {
    
    
        DESKeySpec dks = new DESKeySpec(key);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = keyFactory.generateSecret(dks);
 
        // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码
        // SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
 
        return secretKey;
    }
 
    /**
     * 解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String key) throws Exception {
    
    
        Key k = toKey(decryptBASE64(key));
 
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, k);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String key) throws Exception {
    
    
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, k);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 生成密钥
     * 
     * @return
     * @throws Exception
     */
    public static String initKey() throws Exception {
    
    
        return initKey(null);
    }
 
    /**
     * 生成密钥
     * 
     * @param seed
     * @return
     * @throws Exception
     */
    public static String initKey(String seed) throws Exception {
    
    
        SecureRandom secureRandom = null;
 
        if (seed != null) {
    
    
            secureRandom = new SecureRandom(decryptBASE64(seed));
        } else {
    
    
            secureRandom = new SecureRandom();
        }
 
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
        kg.init(secureRandom);
 
        SecretKey secretKey = kg.generateKey();
 
        return encryptBASE64(secretKey.getEncoded());
    }
}

Continuing the implementation of the previous class, we use MD5 and SHA to encrypt strings to generate keys, which is a relatively common key generation method.
Give another test class:

import static org.junit.Assert.*;
 
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class DESCoderTest {
    
    
 
    @Test
    public void test() throws Exception {
    
    
        String inputStr = "DES";
        String key = DESCoder.initKey();
        System.err.println("原文:\t" + inputStr);
 
        System.err.println("密钥:\t" + key);
 
        byte[] inputData = inputStr.getBytes();
        inputData = DESCoder.encrypt(inputData, key);
 
        System.err.println("加密后:\t" + DESCoder.encryptBASE64(inputData));
 
        byte[] outputData = DESCoder.decrypt(inputData, key);
        String outputStr = new String(outputData);
 
        System.err.println("解密后:\t" + outputStr);
 
        assertEquals(inputStr, outputStr);
    }
}

The resulting output is as follows:

原文:	DES
密钥:	f3wEtRrV6q0=

加密后:	C6qe9oNIzRY=

解密后:	DES

The output obtained from the console, we can compare the results after encryption and decryption. This is a simple encryption and decryption method with only one key.
In fact, DES has many siblings, such as DESede (TripleDES), AES, Blowfish, RC2, RC4 (ARCFOUR). I won’t elaborate too much here, it’s the same, just replace the ALGORITHM with the corresponding value, and at the same time make a code to replace **SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);** It’s all right, and the key length is different .

/**
 * DES          key size must be equal to 56
 * DESede(TripleDES) key size must be equal to 112 or 168
 * AES          key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
 * Blowfish     key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
 * RC2          key size must be between 40 and 1024 bits
 * RC4(ARCFOUR) key size must be between 40 and 1024 bits
 **/

In addition to DES, we also know that there are DESede (TripleDES, that is, 3DES), AES, Blowfish, RC2, RC4 (ARCFOUR) and other symmetric encryption methods, and their implementation methods are similar. Here is another algorithm for symmetric encryption——PBE
PBE
PBE - Password-based encryption (based on password encryption). Its characteristic is that the password is controlled by the user without any physical media; methods such as random number (here we call salt) hash and multiple encryption are used to ensure data security. It is a simple encryption method.
Through the java code to achieve as follows: Coder class see

import java.security.Key;
import java.util.Random;
  
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
  
/**
 * PBE安全编码组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class PBECoder extends Coder {
    
    
    /**
     * 支持以下任意一种算法
     * 
     * <pre>
     * PBEWithMD5AndDES 
     * PBEWithMD5AndTripleDES 
     * PBEWithSHA1AndDESede
     * PBEWithSHA1AndRC2_40
     * </pre>
     */
    public static final String ALGORITHM = "PBEWITHMD5andDES";
  
    /**
     * 盐初始化
     * 
     * @return
     * @throws Exception
     */
    public static byte[] initSalt() throws Exception {
    
    
        byte[] salt = new byte[8];
        Random random = new Random();
        random.nextBytes(salt);
        return salt;
    }
  
    /**
     * 转换密钥<br>
     * 
     * @param password
     * @return
     * @throws Exception
     */
    private static Key toKey(String password) throws Exception {
    
    
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = keyFactory.generateSecret(keySpec);
  
        return secretKey;
    }
  
    /**
     * 加密
     * 
     * @param data 数据
     * @param password 密码
     * @param salt  盐
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String password, byte[] salt)
            throws Exception {
    
    
  
        Key key = toKey(password);
  
        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
  
        return cipher.doFinal(data);
  
    }
  
    /**
     * 解密
     * 
     * @param data  数据
     * @param password 密码
     * @param salt  盐
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String password, byte[] salt)
            throws Exception {
    
    
  
        Key key = toKey(password);
  
        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
  
        return cipher.doFinal(data);
  
    }
}

Give another test class:

import static org.junit.Assert.*;
  
import org.junit.Test;
  
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class PBECoderTest {
    
    
  
    @Test
    public void test() throws Exception {
    
    
        String inputStr = "abc";
        System.err.println("原文: " + inputStr);
        byte[] input = inputStr.getBytes();
  
        String pwd = "efg";
        System.err.println("密码: " + pwd);
  
        byte[] salt = PBECoder.initSalt();
  
        byte[] data = PBECoder.encrypt(input, pwd, salt);
  
        System.err.println("加密后: " + PBECoder.encryptBASE64(data));
  
        byte[] output = PBECoder.decrypt(data, pwd, salt);
        String outputStr = new String(output);
  
        System.err.println("解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
    }
  
}

Console output:

原文: abc
密码: efg
加密后: iCZ0uRtaAhE=
 
解密后: abc

Later we will introduce asymmetric encryption algorithms, such as RSA, DSA, DH, ECC, etc.

Next we introduce a typical asymmetric encryption algorithm - RSA

The RSA
algorithm appeared in 1978. It is the first algorithm that can be used for both data encryption and digital signature. It is easy to understand and operate, and it is also popular. Algorithms are named after their inventors: Ron Rivest, AdiShamir and Leonard Adleman.
The feature of this encryption algorithm is mainly the change of the key. We saw above that DES has only one key. It is equivalent to only one key. If the key is lost, the data will not be safe. RSA has two keys at the same time, public key and private key. Also supports digital signatures. The significance of digital signature is to verify the transmitted data. Make sure that the data is not modified during the transfer project.

Process analysis:

  1. Party A builds a key pair, publishes the public key to Party B, and keeps the private key.
  2. Party A encrypts the data with the private key, then signs the encrypted data with the private key, and sends the signature and encrypted data to Party B; Party B uses the public key and signature to verify whether the data to be decrypted is valid. decrypt.
  3. Party B encrypts the data with the public key and sends the encrypted data to Party A; Party A obtains the encrypted data and decrypts it with the private key.

According to the above steps, the sequence diagram is given as follows:

  1. Various Java encryption algorithms
  2. Various Java encryption algorithms
  3. Various Java encryption algorithms

Through the java code to achieve as follows: Coder class see

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.crypto.Cipher;
 
/**
 * RSA安全编码组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class RSACoder extends Coder {
    
    
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
 
    private static final String PUBLIC_KEY = "RSAPublicKey";
    private static final String PRIVATE_KEY = "RSAPrivateKey";
 
    /**
     * 用私钥对信息生成数字签名
     * 
     * @param data
     *            加密数据
     * @param privateKey
     *            私钥
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
    
    
        // 解密由base64编码的私钥
        byte[] keyBytes = decryptBASE64(privateKey);
 
        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
 
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
 
        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
 
        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
 
        return encryptBASE64(signature.sign());
    }
 
    /**
     * 校验数字签名
     * 
     * @param data
     *            加密数据
     * @param publicKey
     *            公钥
     * @param sign
     *            数字签名
     * 
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     * 
     */
    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
    
    
 
        // 解密由base64编码的公钥
        byte[] keyBytes = decryptBASE64(publicKey);
 
        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
 
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
 
        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
 
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
 
        // 验证签名是否正常
        return signature.verify(decryptBASE64(sign));
    }
 
    /**
     * 解密<br>
     * 用私钥解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String key)
            throws Exception {
    
    
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);
 
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
 
        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 解密<br>
     * 用私钥解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String key)
            throws Exception {
    
    
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);
 
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);
 
        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 加密<br>
     * 用公钥加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String key)
            throws Exception {
    
    
        // 对公钥解密
        byte[] keyBytes = decryptBASE64(key);
 
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 加密<br>
     * 用私钥加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String key)
            throws Exception {
    
    
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);
 
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 取得私钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PRIVATE_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 取得公钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PUBLIC_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 初始化密钥
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
    
    
        KeyPairGenerator keyPairGen = KeyPairGenerator
                .getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
 
        KeyPair keyPair = keyPairGen.generateKeyPair();
 
        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
 
        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
 
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
}

Give another test class:

import static org.junit.Assert.*;
 
import org.junit.Before;
import org.junit.Test;
 
import java.util.Map;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class RSACoderTest {
    
    
    private String publicKey;
    private String privateKey;
 
    @Before
    public void setUp() throws Exception {
    
    
        Map<String, Object> keyMap = RSACoder.initKey();
 
        publicKey = RSACoder.getPublicKey(keyMap);
        privateKey = RSACoder.getPrivateKey(keyMap);
        System.err.println("公钥: \n\r" + publicKey);
        System.err.println("私钥: \n\r" + privateKey);
    }
 
    @Test
    public void test() throws Exception {
    
    
        System.err.println("公钥加密——私钥解密");
        String inputStr = "abc";
        byte[] data = inputStr.getBytes();
 
        byte[] encodedData = RSACoder.encryptByPublicKey(data, publicKey);
 
        byte[] decodedData = RSACoder.decryptByPrivateKey(encodedData,
                privateKey);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
 
    }
 
    @Test
    public void testSign() throws Exception {
    
    
        System.err.println("私钥加密——公钥解密");
        String inputStr = "sign";
        byte[] data = inputStr.getBytes();
 
        byte[] encodedData = RSACoder.encryptByPrivateKey(data, privateKey);
 
        byte[] decodedData = RSACoder
                .decryptByPublicKey(encodedData, publicKey);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
 
        System.err.println("私钥签名——公钥验证签名");
        // 产生签名
        String sign = RSACoder.sign(encodedData, privateKey);
        System.err.println("签名:\r" + sign);
 
        // 验证签名
        boolean status = RSACoder.verify(encodedData, publicKey, sign);
        System.err.println("状态:\r" + status);
        assertTrue(status);
 
    }
 
}

Console output:

公钥: 

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYU/+I0+z1aBl5X6DUUOHQ7FZpmBSDbKTtx89J
EcB64jFCkunELT8qiKly7fzEqD03g8ALlu5XvX+bBqHFy7YPJJP0ekE2X3wjUnh2NxlqpH3/B/xm
1ZdSlCwDIkbijhBVDjA/bu5BObhZqQmDwIxlQInL9oVz+o6FbAZCyHBd7wIDAQAB

私钥: 

MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhT/4jT7PVoGXlfoNRQ4dDsVmmY
FINspO3Hz0kRwHriMUKS6cQtPyqIqXLt/MSoPTeDwAuW7le9f5sGocXLtg8kk/R6QTZffCNSeHY3
GWqkff8H/GbVl1KULAMiRuKOEFUOMD9u7kE5uFmpCYPAjGVAicv2hXP6joVsBkLIcF3vAgMBAAEC
gYBvZHWoZHmS2EZQqKqeuGr58eobG9hcZzWQoJ4nq/CarBAjw/VovUHE490uK3S9ht4FW7Yzg3LV
/MB06Huifh6qf/X9NQA7SeZRRC8gnCQk6JuDIEVJOud5jU+9tyumJakDKodQ3Jf2zQtNr+5ZdEPl
uwWgv9c4kmpjhAdyMuQmYQJBANn6pcgvyYaia52dnu+yBUsGkaFfwXkzFSExIbi0MXTkhEb/ER/D
rLytukkUu5S5ecz/KBa8U4xIslZDYQbLz5ECQQCy5dutt7RsxN4+dxCWn0/1FrkWl2G329Ucewm3
QU9CKu4D+7Kqdj+Ha3lXP8F0Etaaapi7+EfkRUpukn2ItZV/AkEAlk+I0iphxT1rCB0Q5CjWDY5S
Df2B5JmdEG5Y2o0nLXwG2w44OLct/k2uD4cEcuITY5Dvi/4BftMCZwm/dnhEgQJACIktJSnJwxLV
o9dchENPtlsCM9C/Sd2EWpqISSUlmfugZbJBwR5pQ5XeMUqKeXZYpP+HEBj1nS+tMH9u2/IGEwJA
fL8mZiZXan/oBKrblAbplNcKWGRVD/3y65042PAEeghahlJMiYquV5DzZajuuT0wbJ5xQuZB01+X
nfpFpBJ2dw==

公钥加密——私钥解密
加密前: abc

解密后: abc
公钥: 

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdOj40yEB48XqWxmPILmJAc7UecIN7F32etSHF
9rwbuEh3+iTPOGSxhoSQpOED0vOb0ZIMkBXZSgsxLaBSin2RZ09YKWRjtpCA0kDkiD11gj4tzTiM
l9qq1kwSK7ZkGAgodEn3yIILVmQDuEImHOXFtulvJ71ka07u3LuwUNdB/wIDAQAB

私钥: 

MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN06PjTIQHjxepbGY8guYkBztR5w
g3sXfZ61IcX2vBu4SHf6JM84ZLGGhJCk4QPS85vRkgyQFdlKCzEtoFKKfZFnT1gpZGO2kIDSQOSI
PXWCPi3NOIyX2qrWTBIrtmQYCCh0SffIggtWZAO4QiYc5cW26W8nvWRrTu7cu7BQ10H/AgMBAAEC
gYEAz2JWBizjI31bqhP4XiP9PuY5F3vqBW4T+L9cFbQiyumKJc58yzTWUAUGKIIn3enXLG7dNqGr
mbJro4JeFIJ3CiVDpXR9+FluIgI4SXm7ioGKF2NOMA9LR5Fu82W+pLfpTN2y2SaLYWEDZyp53BxY
j9gUxaxi1MQs+C1ZgDF2xmECQQDy70bQntbRfysP+ppCtd56YRnES1Tyekw0wryS2tr+ivQJl7JF
gp5rPAOXpgrq36xHDwUspQ0sJ0vj0O7ywxr1AkEA6SAaLhrJJrYucC0jxwAhUYyaPN+aOsWymaRh
9jA/Wc0wp29SbGTh5CcMuGpXm1g0M+FKW3dGiHgS3rVUKim4owJAbnxgapUzAgiiHxxMeDaavnHW
9C2GrtjsO7qtZOTgYI/1uT8itvZW8lJTF+9OW8/qXE76fXl7ai9dFnl5kzMk2QJBALfHz/vCsArt
mkRiwY6zApE4Z6tPl1V33ymSVovvUzHnOdD1SKQdD5t+UV/crb3QVi8ED0t2B0u0ZSPfDT/D7kMC
QDpwdj9k2F5aokLHBHUNJPFDAp7a5QMaT64gv/d48ITJ68Co+v5WzLMpzJBYXK6PAtqIhxbuPEc2
I2k1Afmrwyw=

私钥加密——公钥解密
加密前: sign

解密后: sign
私钥签名——公钥验证签名
签名:
ud1RsIwmSC1pN22I4IXteg1VD2FbiehKUfNxgVSHzvQNIK+d20FCkHCqh9djP3h94iWnIUY0ifU+
mbJkhAl/i5krExOE0hknOnPMcEP+lZV1RbJI2zG2YooSp2XDleqrQk5e/QF2Mx0Zxt8Xsg7ucVpn
i3wwbYWs9wSzIf0UjlM=

状态:
true

To briefly summarize, using public key encryption and private key decryption, a data transfer from Party B to Party A is completed, through private key encryption, public key decryption, and at the same time, through private key signature and public key verification signature, a data transmission from Party A to Party A is completed. Party B's data transfer and verification, two data transfers complete a complete set of data interaction!

Similar to digital signatures, digital envelopes are described as follows:

Digital envelopes
Digital envelopes use encryption to ensure that only the intended recipient can read the contents of the letter.
Process:
The information sender uses a symmetric key to encrypt the information, and then uses the receiver's public key to encrypt the symmetric key (this part is called a digital envelope), and then sends it to the receiver together with the information; the receiver first Open the digital envelope with the corresponding private key to get the symmetric key, and then use the symmetric key to decrypt the information.

Next we analyze the DH encryption algorithm, an encryption algorithm based on a key agreement protocol.
DH
Diffie-Hellman algorithm (DH algorithm), key consensus protocol. It is an idea proposed by Diffie and Hellman, the founders of the public key cryptosystem. Simply put, it allows two users to exchange information on public media to generate a "consistent" key that can be shared. In other words, Party A produces a pair of keys (public key, private key), and Party B generates a key pair (public key, private key) of Party B according to Party A's public key. This is the baseline and the basis for data transmission confidentiality. At the same time, both parties use the same symmetric encryption algorithm to construct a local key (SecretKey) to encrypt data. In this way, after exchanging the local key (SecretKey) algorithm, both parties A and B disclose their public keys, use the other party's public key and the private key just generated to encrypt data, and can use the other party's public key and their own private key to encrypt data. decrypt. Not only the two parties, Party A and Party B, but also can be expanded to multi-party shared data communication, thus completing the secure communication of network interactive data! The algorithm is derived from the Chinese congruence theorem - the Chinese remainder theorem.

Process analysis:

1. Party A builds a key pair, announces the public key to Party B, and keeps the private key; the two parties agree on a data encryption algorithm; key reserved.
2. Party A uses the private key, Party B's public key, and the agreed data encryption algorithm to construct a local key, then encrypts the data with the local key, and sends the encrypted data to Party B; Party B uses the private key, Party A's public key, and the agreed data to encrypt The algorithm builds a local key, and then decrypts the data through the local key.
3. Party B uses the private key, Party A’s public key, and the agreed data encryption algorithm to construct a local key, then encrypts the data with the local key, and sends the encrypted data to Party A; Party A uses the private key, Party B’s public key, and the agreed data The encryption algorithm builds a local key, and then decrypts the data through the local key.

Various Java encryption algorithms

  1. Various Java encryption algorithms
  2. Various Java encryption algorithms

Through the java code to achieve as follows: Coder class see

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
 
/**
 * DH安全编码组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class DHCoder extends Coder {
    
    
    public static final String ALGORITHM = "DH";
 
    /**
     * 默认密钥字节数
     * 
     * <pre>
     * DH
     * Default Keysize 1024  
     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
     * </pre>
     */
    private static final int KEY_SIZE = 1024;
 
    /**
     * DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。
     */
    public static final String SECRET_ALGORITHM = "DES";
    private static final String PUBLIC_KEY = "DHPublicKey";
    private static final String PRIVATE_KEY = "DHPrivateKey";
 
    /**
     * 初始化甲方密钥
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
    
    
        KeyPairGenerator keyPairGenerator = KeyPairGenerator
                .getInstance(ALGORITHM);
        keyPairGenerator.initialize(KEY_SIZE);
 
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
 
        // 甲方公钥
        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
 
        // 甲方私钥
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
 
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
 
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
 
    /**
     * 初始化乙方密钥
     * 
     * @param key
     *            甲方公钥
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey(String key) throws Exception {
    
    
        // 解析甲方公钥
        byte[] keyBytes = decryptBASE64(key);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
 
        // 由甲方公钥构建乙方密钥
        DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
 
        KeyPairGenerator keyPairGenerator = KeyPairGenerator
                .getInstance(keyFactory.getAlgorithm());
        keyPairGenerator.initialize(dhParamSpec);
 
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
 
        // 乙方公钥
        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
 
        // 乙方私钥
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
 
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
 
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
 
        return keyMap;
    }
 
    /**
     * 加密<br>
     * 
     * @param data
     *            待加密数据
     * @param publicKey
     *            甲方公钥
     * @param privateKey
     *            乙方私钥
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String publicKey,
            String privateKey) throws Exception {
    
    
 
        // 生成本地密钥
        SecretKey secretKey = getSecretKey(publicKey, privateKey);
 
        // 数据加密
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 解密<br>
     * 
     * @param data
     *            待解密数据
     * @param publicKey
     *            乙方公钥
     * @param privateKey
     *            乙方私钥
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String publicKey,
            String privateKey) throws Exception {
    
    
 
        // 生成本地密钥
        SecretKey secretKey = getSecretKey(publicKey, privateKey);
        // 数据解密
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
 
        return cipher.doFinal(data);
    }
 
    /**
     * 构建密钥
     * 
     * @param publicKey
     *            公钥
     * @param privateKey
     *            私钥
     * @return
     * @throws Exception
     */
    private static SecretKey getSecretKey(String publicKey, String privateKey)
            throws Exception {
    
    
        // 初始化公钥
        byte[] pubKeyBytes = decryptBASE64(publicKey);
 
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
 
        // 初始化私钥
        byte[] priKeyBytes = decryptBASE64(privateKey);
 
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
        Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);
 
        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory
                .getAlgorithm());
        keyAgree.init(priKey);
        keyAgree.doPhase(pubKey, true);
 
        // 生成本地密钥
        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
 
        return secretKey;
    }
 
    /**
     * 取得私钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PRIVATE_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 取得公钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PUBLIC_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
}

Give another test class:

import static org.junit.Assert.*;
 
import java.util.Map;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class DHCoderTest {
    
    
 
    @Test
    public void test() throws Exception {
    
    
        // 生成甲方密钥对儿
        Map<String, Object> aKeyMap = DHCoder.initKey();
        String aPublicKey = DHCoder.getPublicKey(aKeyMap);
        String aPrivateKey = DHCoder.getPrivateKey(aKeyMap);
 
        System.err.println("甲方公钥:\r" + aPublicKey);
        System.err.println("甲方私钥:\r" + aPrivateKey);
         
        // 由甲方公钥产生本地密钥对儿
        Map<String, Object> bKeyMap = DHCoder.initKey(aPublicKey);
        String bPublicKey = DHCoder.getPublicKey(bKeyMap);
        String bPrivateKey = DHCoder.getPrivateKey(bKeyMap);
         
        System.err.println("乙方公钥:\r" + bPublicKey);
        System.err.println("乙方私钥:\r" + bPrivateKey);
         
        String aInput = "abc ";
        System.err.println("原文: " + aInput);
 
        // 由甲方公钥,乙方私钥构建密文
        byte[] aCode = DHCoder.encrypt(aInput.getBytes(), aPublicKey,
                bPrivateKey);
 
        // 由乙方公钥,甲方私钥解密
        byte[] aDecode = DHCoder.decrypt(aCode, bPublicKey, aPrivateKey);
        String aOutput = (new String(aDecode));
 
        System.err.println("解密: " + aOutput);
 
        assertEquals(aInput, aOutput);
 
        System.err.println(" ===============反过来加密解密================== ");
        String bInput = "def ";
        System.err.println("原文: " + bInput);
 
        // 由乙方公钥,甲方私钥构建密文
        byte[] bCode = DHCoder.encrypt(bInput.getBytes(), bPublicKey,
                aPrivateKey);
 
        // 由甲方公钥,乙方私钥解密
        byte[] bDecode = DHCoder.decrypt(bCode, aPublicKey, bPrivateKey);
        String bOutput = (new String(bDecode));
 
        System.err.println("解密: " + bOutput);
 
        assertEquals(bInput, bOutput);
    }
 
}

Console output:

甲方公钥:
MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAdAWBVmIzqcko
Ej6qFjLDL2+Y3FPq1iRbnOyOpDj71yKaK1K+FhTv04B0zy4DKcvAASV7/Gv0W+bgqdmffRkqrQ==

甲方私钥:
MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjACJRfy1LyR
eHyD+4Hfb+xR0uoIGR1oL9i9Nk6g2AAuaDPgEVWHn+QXID13yL/uDos=

乙方公钥:
MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAVEYSfBA+I9nr
dWw3OBv475C+eBrWBBYqt0m6/eu4ptuDQHwV4MmUtKAC2wc2nNrdb1wmBhY1X8RnWkJ1XmdDbQ==

乙方私钥:
MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAqaZiCdXp
2iNpdBlHRaO9ir70wo2n32xNlIzIX19VLSPCDdeUWkgRv4CEj/8k+/yd

原文: abc 
解密: abc 
 ===============反过来加密解密================== 
原文: def 
解密: def

As I said, after obtaining the public key of the other party, both parties can encrypt the data sent to the other party, and at the same time decrypt the received data, achieving the purpose of data security communication!

Next we introduce DSA digital signature, another implementation of asymmetric encryption.
DSA
DSA-Digital Signature Algorithm is a variant of the Schnorr and ElGamal signature algorithms, and is regarded as DSS (DigitalSignature Standard) by the US NIST. Simply put, this is a more advanced verification method used as a digital signature. There are not only public keys, private keys, but also digital signatures. Private key encryption generates digital signatures, and public key verifies data and signatures. If the data and the signature do not match then the verification is considered to have failed! The function of the digital signature is to verify that the data has not been modified during transmission. Digital signature is an upgrade of one-way encryption!

  1. Various Java encryption algorithms
  2. Various Java encryption algorithms

Through the java code to achieve as follows: Coder class see

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
/**
 * DSA安全编码组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class DSACoder extends Coder {
    
    
 
    public static final String ALGORITHM = "DSA";
 
    /**
     * 默认密钥字节数
     * 
     * <pre>
     * DSA 
     * Default Keysize 1024  
     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
     * </pre>
     */
    private static final int KEY_SIZE = 1024;
 
    /**
     * 默认种子
     */
    private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3";
 
    private static final String PUBLIC_KEY = "DSAPublicKey";
    private static final String PRIVATE_KEY = "DSAPrivateKey";
 
    /**
     * 用私钥对信息生成数字签名
     * 
     * @param data
     *            加密数据
     * @param privateKey
     *            私钥
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
    
    
        // 解密由base64编码的私钥
        byte[] keyBytes = decryptBASE64(privateKey);
 
        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
 
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
 
        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
 
        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
        signature.initSign(priKey);
        signature.update(data);
 
        return encryptBASE64(signature.sign());
    }
 
    /**
     * 校验数字签名
     * 
     * @param data
     *            加密数据
     * @param publicKey
     *            公钥
     * @param sign
     *            数字签名
     * 
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     * 
     */
    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
    
    
 
        // 解密由base64编码的公钥
        byte[] keyBytes = decryptBASE64(publicKey);
 
        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
 
        // ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
 
        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
 
        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
        signature.initVerify(pubKey);
        signature.update(data);
 
        // 验证签名是否正常
        return signature.verify(decryptBASE64(sign));
    }
 
    /**
     * 生成密钥
     * 
     * @param seed
     *            种子
     * @return 密钥对象
     * @throws Exception
     */
    public static Map<String, Object> initKey(String seed) throws Exception {
    
    
        KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);
        // 初始化随机产生器
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.setSeed(seed.getBytes());
        keygen.initialize(KEY_SIZE, secureRandom);
 
        KeyPair keys = keygen.genKeyPair();
 
        DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();
        DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();
 
        Map<String, Object> map = new HashMap<String, Object>(2);
        map.put(PUBLIC_KEY, publicKey);
        map.put(PRIVATE_KEY, privateKey);
 
        return map;
    }
 
    /**
     * 默认生成密钥
     * 
     * @return 密钥对象
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
    
    
        return initKey(DEFAULT_SEED);
    }
 
    /**
     * 取得私钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PRIVATE_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 取得公钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PUBLIC_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
}

Give another test class:

import static org.junit.Assert.*;
 
import java.util.Map;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class DSACoderTest {
    
    
 
    @Test
    public void test() throws Exception {
    
    
        String inputStr = "abc";
        byte[] data = inputStr.getBytes();
 
        // 构建密钥
        Map<String, Object> keyMap = DSACoder.initKey();
 
        // 获得密钥
        String publicKey = DSACoder.getPublicKey(keyMap);
        String privateKey = DSACoder.getPrivateKey(keyMap);
 
        System.err.println("公钥:\r" + publicKey);
        System.err.println("私钥:\r" + privateKey);
 
        // 产生签名
        String sign = DSACoder.sign(data, privateKey);
        System.err.println("签名:\r" + sign);
 
        // 验证签名
        boolean status = DSACoder.verify(data, publicKey, sign);
        System.err.println("状态:\r" + status);
        assertTrue(status);
 
    }
 
}

Console output:

公钥:
MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZp
RV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fn
xqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuE
C/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ
FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo
g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAIu4RUlcQLp49PI0MrbssOY+3uySVnp0TULSv
5T4VaHoKzsLHgGTrwOvsGA+V3yCNl2WDu3D84bSLF7liTWgOj+SMOEaPk4VyRTlLXZWGPsf1Mfd9
21XAbMeVyKDSHHVGbMjBScajf3bXooYQMlyoHiOt/WrCo+mv7efstMM0PGo=

私钥:
MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2
USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4
O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB
gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR
kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFwIVAIegLUtmm2oQKQJTOiLugHTSjl/q

签名:
MC0CFQCMg0J/uZmF8GuRpr3TNq48w60nDwIUJCyYNah+HtbU6NcQfy8Ac6LeLQs=

状态:
true

Note that if the status is true, the verification is successful!

ECC
ECC-Elliptic Curves Cryptography, elliptic curve cryptography, is a system that provides the highest encryption strength per bit among the known public key systems. It plays a great role in software registration protection, and general serial numbers are usually generated by this algorithm.
When I started to sort out "Java Encryption Technology (2)", I had already started to study ECC, but there are too few materials about Java's implementation of ECC algorithms, whether it is domestic or foreign materials, whether it is official or For the unofficial explanation, there is only one answer in the end - the ECC algorithm is supported after jdk1.5, and currently only the generation and analysis of the key can be completed. If you want to implement the ECC algorithm, you need to call the hardware to complete the encryption/decryption (the ECC algorithm is quite resource-intensive, and if you simply use the CPU for encryption/decryption, the efficiency is low), involving the field of Java Card, PKCS#11. In fact, PKCS#11 configuration is very simple, but lack of hardware equipment, can not try!

Nevertheless, I still provide the corresponding Java implementation code for your reference.

Through the java code to achieve as follows: Coder class see

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
 
import sun.security.ec.ECKeyFactory;
import sun.security.ec.ECPrivateKeyImpl;
import sun.security.ec.ECPublicKeyImpl;
 
/**
 * ECC安全编码组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class ECCCoder extends Coder {
    
    
 
    public static final String ALGORITHM = "EC";
    private static final String PUBLIC_KEY = "ECCPublicKey";
    private static final String PRIVATE_KEY = "ECCPrivateKey";
 
    /**
     * 解密<br>
     * 用私钥解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String key) throws Exception {
    
    
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);
 
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
 
        ECPrivateKey priKey = (ECPrivateKey) keyFactory
                .generatePrivate(pkcs8KeySpec);
 
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(),
                priKey.getParams());
 
        // 对数据解密
        // TODO Chipher不支持EC算法 未能实现
        Cipher cipher = new NullCipher();
        // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
        cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());
 
        return cipher.doFinal(data);
    }
 
    /**
     * 加密<br>
     * 用公钥加密
     * 
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String privateKey)
            throws Exception {
    
    
        // 对公钥解密
        byte[] keyBytes = decryptBASE64(privateKey);
 
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
 
        ECPublicKey pubKey = (ECPublicKey) keyFactory
                .generatePublic(x509KeySpec);
 
        ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(),
                pubKey.getParams());
 
        // 对数据加密
        // TODO Chipher不支持EC算法 未能实现
        Cipher cipher = new NullCipher();
        // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());
 
        return cipher.doFinal(data);
    }
 
    /**
     * 取得私钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PRIVATE_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 取得公钥
     * 
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
    
    
        Key key = (Key) keyMap.get(PUBLIC_KEY);
 
        return encryptBASE64(key.getEncoded());
    }
 
    /**
     * 初始化密钥
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
    
    
        BigInteger x1 = new BigInteger(
                "2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8", 16);
        BigInteger x2 = new BigInteger(
                "289070fb05d38ff58321f2e800536d538ccdaa3d9", 16);
 
        ECPoint g = new ECPoint(x1, x2);
 
        // the order of generator
        BigInteger n = new BigInteger(
                "5846006549323611672814741753598448348329118574063", 10);
        // the cofactor
        int h = 2;
        int m = 163;
        int[] ks = {
    
     7, 6, 3 };
        ECFieldF2m ecField = new ECFieldF2m(m, ks);
        // y^2+xy=x^3+x^2+1
        BigInteger a = new BigInteger("1", 2);
        BigInteger b = new BigInteger("1", 2);
 
        EllipticCurve ellipticCurve = new EllipticCurve(ecField, a, b);
 
        ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g,
                n, h);
        // 公钥
        ECPublicKey publicKey = new ECPublicKeyImpl(g, ecParameterSpec);
 
        BigInteger s = new BigInteger(
                "1234006549323611672814741753598448348329118574063", 10);
        // 私钥
        ECPrivateKey privateKey = new ECPrivateKeyImpl(s, ecParameterSpec);
 
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
 
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
 
        return keyMap;
    }
 
}

Please pay attention to the TODO content in the above code , and remind you again that Chipher does not support the EC algorithm, and the above code is for reference only. Chipher, Signature, KeyPairGenerator, KeyAgreement, and SecretKey do not support the EC algorithm. In order to ensure that the program can be executed normally, we use the NullCipher class, the verification program.

Provide a test class as usual:

import static org.junit.Assert.*;
 
import java.math.BigInteger;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.util.Map;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class ECCCoderTest {
    
    
 
    @Test
    public void test() throws Exception {
    
    
        String inputStr = "abc";
        byte[] data = inputStr.getBytes();
 
        Map<String, Object> keyMap = ECCCoder.initKey();
 
        String publicKey = ECCCoder.getPublicKey(keyMap);
        String privateKey = ECCCoder.getPrivateKey(keyMap);
        System.err.println("公钥: \n" + publicKey);
        System.err.println("私钥: \n" + privateKey);
 
        byte[] encodedData = ECCCoder.encrypt(data, publicKey);
 
        byte[] decodedData = ECCCoder.decrypt(encodedData, privateKey);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
    }
}

Console output:

公钥: 
MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEAv4TwFN7vBGsqgfXk95ObV5clO7oAokHD7BdOP9YMh8u
gAU21TjM2qPZ

私钥: 
MDICAQAwEAYHKoZIzj0CAQYFK4EEAAEEGzAZAgEBBBTYJsR3BN7TFw7JHcAHFkwNmfil7w==

加密前: abc

解密后: abc

The main content of this article is the implementation of the Java certificate system.

Before building the Java code implementation, we need to complete the production of the certificate.
1. Generate the keyStroe file
Execute the following command on the command line:

keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:\zlex.keystore

Among them
, -genkey means to generate a key
-validity specifies the validity period of the certificate, here is 36000 days
-alias specifies the alias, here is www.zlex.org
-keyalg specifies the algorithm, here is RSA
-keystore specifies the storage location, here is d:\zlex. keystore

The password I use here is 123456

Console output:

输入keystore密码:
再次输入新密码:
您的名字与姓氏是什么?
  [Unknown]:  www.zlex.org
您的组织单位名称是什么?
  [Unknown]:  zlex
您的组织名称是什么?
  [Unknown]:  zlex
您所在的城市或区域名称是什么?
  [Unknown]BJ
您所在的州或省份名称是什么?
  [Unknown]BJ
该单位的两字母国家代码是什么
  [Unknown]CN
CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗?
  []Y

输入<tomcat>的主密码
        (如果和 keystore 密码相同,按回车):
再次输入新密码:

At this time, a zlex.keystore file will be generated under the D disk.

2. Generate a self-signed certificate.
It is not enough to have a keyStore file, and a certificate file is also required. The certificate is the public key certificate directly provided to the outside world.
Export the certificate:

keytool -export -keystore d:\zlex.keystore -alias www.zlex.org -file d:\zlex.cer -rfc

Where
-export is specified as the export operation
-keystore specifies the keystore file
-alias specifies the alias in the exported keystore file
-file points to the export path
-rfc is output in text format, that is, output in BASE64 encoding
The password here is 123456

Console output:

输入keystore密码:
保存在文件中的认证 <d:\zlex.cer>

Of course, the user needs to import the certificate!
The construction of the CAS single sign-on system can be completed through self-signed certificates!

Ok, the preparatory work is complete, and the Java implementation begins!

Through the java code to achieve as follows: Coder class see

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
 
import javax.crypto.Cipher;
 
/**
 * 证书组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class CertificateCoder extends Coder {
    
    
 
 
    /**
     * Java密钥库(Java Key Store,JKS)KEY_STORE
     */
    public static final String KEY_STORE = "JKS";
 
    public static final String X509 = "X.509";
 
    /**
     * 由KeyStore获得私钥
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    private static PrivateKey getPrivateKey(String keyStorePath, String alias,
            String password) throws Exception {
    
    
        KeyStore ks = getKeyStore(keyStorePath, password);
        PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
        return key;
    }
 
    /**
     * 由Certificate获得公钥
     * 
     * @param certificatePath
     * @return
     * @throws Exception
     */
    private static PublicKey getPublicKey(String certificatePath)
            throws Exception {
    
    
        Certificate certificate = getCertificate(certificatePath);
        PublicKey key = certificate.getPublicKey();
        return key;
    }
 
    /**
     * 获得Certificate
     * 
     * @param certificatePath
     * @return
     * @throws Exception
     */
    private static Certificate getCertificate(String certificatePath)
            throws Exception {
    
    
        CertificateFactory certificateFactory = CertificateFactory
                .getInstance(X509);
        FileInputStream in = new FileInputStream(certificatePath);
 
        Certificate certificate = certificateFactory.generateCertificate(in);
        in.close();
 
        return certificate;
    }
 
    /**
     * 获得Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    private static Certificate getCertificate(String keyStorePath,
            String alias, String password) throws Exception {
    
    
        KeyStore ks = getKeyStore(keyStorePath, password);
        Certificate certificate = ks.getCertificate(alias);
 
        return certificate;
    }
 
    /**
     * 获得KeyStore
     * 
     * @param keyStorePath
     * @param password
     * @return
     * @throws Exception
     */
    private static KeyStore getKeyStore(String keyStorePath, String password)
            throws Exception {
    
    
        FileInputStream is = new FileInputStream(keyStorePath);
        KeyStore ks = KeyStore.getInstance(KEY_STORE);
        ks.load(is, password.toCharArray());
        is.close();
        return ks;
    }
 
    /**
     * 私钥加密
     * 
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {
    
    
        // 取得私钥
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 私钥解密
     * 
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {
    
    
        // 取得私钥
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 公钥加密
     * 
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {
    
    
 
        // 取得公钥
        PublicKey publicKey = getPublicKey(certificatePath);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 公钥解密
     * 
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {
    
    
        // 取得公钥
        PublicKey publicKey = getPublicKey(certificatePath);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 验证Certificate
     * 
     * @param certificatePath
     * @return
     */
    public static boolean verifyCertificate(String certificatePath) {
    
    
        return verifyCertificate(new Date(), certificatePath);
    }
 
    /**
     * 验证Certificate是否过期或无效
     * 
     * @param date
     * @param certificatePath
     * @return
     */
    public static boolean verifyCertificate(Date date, String certificatePath) {
    
    
        boolean status = true;
        try {
    
    
            // 取得证书
            Certificate certificate = getCertificate(certificatePath);
            // 验证证书是否过期或无效
            status = verifyCertificate(date, certificate);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 验证证书是否过期或无效
     * 
     * @param date
     * @param certificate
     * @return
     */
    private static boolean verifyCertificate(Date date, Certificate certificate) {
    
    
        boolean status = true;
        try {
    
    
            X509Certificate x509Certificate = (X509Certificate) certificate;
            x509Certificate.checkValidity(date);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 签名
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] sign, String keyStorePath, String alias,
            String password) throws Exception {
    
    
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(
                keyStorePath, alias, password);
        // 获取私钥
        KeyStore ks = getKeyStore(keyStorePath, password);
        // 取得私钥
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
                .toCharArray());
 
        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initSign(privateKey);
        signature.update(sign);
        return encryptBASE64(signature.sign());
    }
 
    /**
     * 验证签名
     * 
     * @param data
     * @param sign
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data, String sign,
            String certificatePath) throws Exception {
    
    
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
        // 获得公钥
        PublicKey publicKey = x509Certificate.getPublicKey();
        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initVerify(publicKey);
        signature.update(data);
 
        return signature.verify(decryptBASE64(sign));
 
    }
 
    /**
     * 验证Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     */
    public static boolean verifyCertificate(Date date, String keyStorePath,
            String alias, String password) {
    
    
        boolean status = true;
        try {
    
    
            Certificate certificate = getCertificate(keyStorePath, alias,
                    password);
            status = verifyCertificate(date, certificate);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 验证Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     */
    public static boolean verifyCertificate(String keyStorePath, String alias,
            String password) {
    
    
        return verifyCertificate(new Date(), keyStorePath, alias, password);
    }
}

Give another test class:

import static org.junit.Assert.*;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CertificateCoderTest {
    
    
    private String password = "123456";
    private String alias = "www.zlex.org";
    private String certificatePath = "d:/zlex.cer";
    private String keyStorePath = "d:/zlex.keystore";
 
    @Test
    public void test() throws Exception {
    
    
        System.err.println("公钥加密——私钥解密");
        String inputStr = "Ceritifcate";
        byte[] data = inputStr.getBytes();
 
        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
                certificatePath);
 
        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                keyStorePath, alias, password);
        String outputStr = new String(decrypt);
 
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
 
        // 验证数据一致
        assertArrayEquals(data, decrypt);
 
        // 验证证书有效
        assertTrue(CertificateCoder.verifyCertificate(certificatePath));
 
    }
 
    @Test
    public void testSign() throws Exception {
    
    
        System.err.println("私钥加密——公钥解密");
 
        String inputStr = "sign";
        byte[] data = inputStr.getBytes();
 
        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
                keyStorePath, alias, password);
 
        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                certificatePath);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
 
        System.err.println("私钥签名——公钥验证签名");
        // 产生签名
        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                password);
        System.err.println("签名:\r" + sign);
 
        // 验证签名
        boolean status = CertificateCoder.verify(encodedData, sign,
                certificatePath);
        System.err.println("状态:\r" + status);
        assertTrue(status);
 
    }
}

Console output:

公钥加密——私钥解密
加密前: Ceritificate

解密后: Ceritificate

私钥加密——公钥解密
加密前: sign

解密后: sign
私钥签名——公钥验证签名
签名:
pqBn5m6PJlfOjH0A6U2o2mUmBsfgyEY1NWCbiyA/I5Gc3gaVNVIdj/zkGNZRqTjhf3+J9a9z9EI7
6F2eWYd7punHx5oh6hfNgcKbVb52EfItl4QEN+djbXiPynn07+Lbg1NOjULnpEd6ZhLP1YwrEAuM
OfvX0e7/wplxLbySaKQ=

状态:
true

This completes the certificate verification system!

Likewise, we can sign code - code signing!
Code signing can be done through the tool JarSigner.
Here we code-sign tools.jar, the command is as follows:

jarsigner -storetype jks -keystore zlex.keystore -verbose tools.jar www.zlex.org

Console output:

输入密钥库的口令短语:
 正在更新: META-INF/WWW_ZLEX.SF
 正在更新: META-INF/WWW_ZLEX.RSA
  正在签名: org/zlex/security/Security.class
  正在签名: org/zlex/tool/Main$1.class
  正在签名: org/zlex/tool/Main$2.class
  正在签名: org/zlex/tool/Main.class

警告:
签名者证书将在六个月内过期。

At this point, we can verify the signed jar!
Verify tools.jar, the command is as follows:

jarsigner -verify -verbose -certs tools.jar

Console output:

         402 Sat Jun 20 16:25:14 CST 2009 META-INF/MANIFEST.MF
         532 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.SF
         889 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.RSA
sm       590 Wed Dec 10 13:03:42 CST 2008 org/zlex/security/Security.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm       705 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$1.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm       779 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$2.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm     12672 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]


  s = 已验证签名
  m = 在清单中列出条目
  k = 在密钥库中至少找到了一个证书
  i = 在身份作用域内至少找到了一个证书

jar 已验证。

警告:
此 jar 包含签名者证书将在六个月内过期的条目。

The purpose of code signing certification is mainly to verify the released software, and supports Sun Java .jar (Java Applet) files (J2SE) and J2ME MIDlet Suite files.

In , we simulate a secure communication over a network based on RSA asymmetric encryption. Now let's take a deeper look at the existing secure network communication - SSL. We need to build a valid certificate issued by the CA, here we use the self-signed certificate zlex.cer
generated above Here, we import the certificate into our keystore.

keytool -import -alias www.zlex.org -file d:/zlex.cer -keystore d:/zlex.keystore

Among them
, -import means to import
-alias specifies the alias, here is www.zlex.org
-file specifies the algorithm, here is d:/zlex.cer
-keystore specifies the storage location, here is d:/zlex.keystore
here I use the password for 654321

Console output:

输入keystore密码:
再次输入新密码:
所有者:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
签发人:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
序列号:4a1e48df
有效期: Thu May 28 16:18:39 CST 2009Wed Aug 26 16:18:39 CST 2009
证书指纹:
         MD5:19:CA:E6:36:E2:DF:AD:96:31:97:2F:A9:AD:FC:37:6A
         SHA1:49:88:30:59:29:45:F1:69:CA:97:A9:6D:8A:CF:08:D2:C3:D5:C0:C4
         签名算法名称:SHA1withRSA
         版本: 3
信任这个认证? []:  y
认证已添加至keystore中

OK, the most complicated preparations are done.
Next, we locate the domain name www.zlex.org on this machine. Open the C:\Windows\System32\drivers\etc\hosts file and bind www.zlex.org to this machine. Append 127.0.0.1 www.zlex.org to the end of the file . Now visit http://www.zlex.org through the address bar , or through the ping command, if the machine can be located, the domain name mapping is done.
Now, configure tomcat. First copy zlex.keystore to the conf directory of tomcat, and then configure server.xml . Add the following content to the configuration file

<Connector
			SSLEnabled="true"
			URIEncoding="UTF-8"
			clientAuth="false"
			keystoreFile="conf/zlex.keystore"
			keystorePass="123456"
			maxThreads="150"
			port="443"
			protocol="HTTP/1.1"
			scheme="https"
			secure="true"
			sslProtocol="TLS" />

Note that clientAuth="false" is set to false during the test phase , and true is recommended for formal use . Now start tomcat, visit https://www.zlex.org/. Obviously, the certificate failed to pass the certification. At this time, you can choose to install the certificate ( the zlex.cerVarious Java encryption algorithms
file above is the certificate), import it as a trusted root certification authority , and restart the browser again (IE, other browsers are for the domain name www .zlex.org does not support local access), visit https://www.zlex.org/, you will see a small lock in the address bar , which means the installation is successful. All browser networking operations are already under the protection of the RSA encryption and decryption system. But it seems we don't feel it. At this time, many people began to doubt, if we want to manually do such an https access, do we need to implement all these functions of the browser? unnecessary!Various Java encryption algorithms

Following the content of the previous article, the following code implementation is given:

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
 
import javax.crypto.Cipher;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
 
/**
 * 证书组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class CertificateCoder extends Coder {
    
    
 
    /**
     * Java密钥库(Java Key Store,JKS)KEY_STORE
     */
    public static final String KEY_STORE = "JKS";
 
    public static final String X509 = "X.509";
    public static final String SunX509 = "SunX509";
    public static final String SSL = "SSL";
 
    /**
     * 由KeyStore获得私钥
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    private static PrivateKey getPrivateKey(String keyStorePath, String alias,
            String password) throws Exception {
    
    
        KeyStore ks = getKeyStore(keyStorePath, password);
        PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
        return key;
    }
 
    /**
     * 由Certificate获得公钥
     * 
     * @param certificatePath
     * @return
     * @throws Exception
     */
    private static PublicKey getPublicKey(String certificatePath)
            throws Exception {
    
    
        Certificate certificate = getCertificate(certificatePath);
        PublicKey key = certificate.getPublicKey();
        return key;
    }
 
    /**
     * 获得Certificate
     * 
     * @param certificatePath
     * @return
     * @throws Exception
     */
    private static Certificate getCertificate(String certificatePath)
            throws Exception {
    
    
        CertificateFactory certificateFactory = CertificateFactory
                .getInstance(X509);
        FileInputStream in = new FileInputStream(certificatePath);
 
        Certificate certificate = certificateFactory.generateCertificate(in);
        in.close();
 
        return certificate;
    }
 
    /**
     * 获得Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    private static Certificate getCertificate(String keyStorePath,
            String alias, String password) throws Exception {
    
    
        KeyStore ks = getKeyStore(keyStorePath, password);
        Certificate certificate = ks.getCertificate(alias);
 
        return certificate;
    }
 
    /**
     * 获得KeyStore
     * 
     * @param keyStorePath
     * @param password
     * @return
     * @throws Exception
     */
    private static KeyStore getKeyStore(String keyStorePath, String password)
            throws Exception {
    
    
        FileInputStream is = new FileInputStream(keyStorePath);
        KeyStore ks = KeyStore.getInstance(KEY_STORE);
        ks.load(is, password.toCharArray());
        is.close();
        return ks;
    }
 
    /**
     * 私钥加密
     * 
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {
    
    
        // 取得私钥
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 私钥解密
     * 
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {
    
    
        // 取得私钥
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 公钥加密
     * 
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {
    
    
 
        // 取得公钥
        PublicKey publicKey = getPublicKey(certificatePath);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 公钥解密
     * 
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {
    
    
        // 取得公钥
        PublicKey publicKey = getPublicKey(certificatePath);
 
        // 对数据加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
 
        return cipher.doFinal(data);
 
    }
 
    /**
     * 验证Certificate
     * 
     * @param certificatePath
     * @return
     */
    public static boolean verifyCertificate(String certificatePath) {
    
    
        return verifyCertificate(new Date(), certificatePath);
    }
 
    /**
     * 验证Certificate是否过期或无效
     * 
     * @param date
     * @param certificatePath
     * @return
     */
    public static boolean verifyCertificate(Date date, String certificatePath) {
    
    
        boolean status = true;
        try {
    
    
            // 取得证书
            Certificate certificate = getCertificate(certificatePath);
            // 验证证书是否过期或无效
            status = verifyCertificate(date, certificate);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 验证证书是否过期或无效
     * 
     * @param date
     * @param certificate
     * @return
     */
    private static boolean verifyCertificate(Date date, Certificate certificate) {
    
    
        boolean status = true;
        try {
    
    
            X509Certificate x509Certificate = (X509Certificate) certificate;
            x509Certificate.checkValidity(date);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 签名
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] sign, String keyStorePath, String alias,
            String password) throws Exception {
    
    
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(
                keyStorePath, alias, password);
        // 获取私钥
        KeyStore ks = getKeyStore(keyStorePath, password);
        // 取得私钥
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
                .toCharArray());
 
        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initSign(privateKey);
        signature.update(sign);
        return encryptBASE64(signature.sign());
    }
 
    /**
     * 验证签名
     * 
     * @param data
     * @param sign
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data, String sign,
            String certificatePath) throws Exception {
    
    
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
        // 获得公钥
        PublicKey publicKey = x509Certificate.getPublicKey();
        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initVerify(publicKey);
        signature.update(data);
 
        return signature.verify(decryptBASE64(sign));
 
    }
 
    /**
     * 验证Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     */
    public static boolean verifyCertificate(Date date, String keyStorePath,
            String alias, String password) {
    
    
        boolean status = true;
        try {
    
    
            Certificate certificate = getCertificate(keyStorePath, alias,
                    password);
            status = verifyCertificate(date, certificate);
        } catch (Exception e) {
    
    
            status = false;
        }
        return status;
    }
 
    /**
     * 验证Certificate
     * 
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     */
    public static boolean verifyCertificate(String keyStorePath, String alias,
            String password) {
    
    
        return verifyCertificate(new Date(), keyStorePath, alias, password);
    }
 
    /**
     * 获得SSLSocektFactory
     * 
     * @param password
     *            密码
     * @param keyStorePath
     *            密钥库路径
     * 
     * @param trustKeyStorePath
     *            信任库路径
     * @return
     * @throws Exception
     */
    private static SSLSocketFactory getSSLSocketFactory(String password,
            String keyStorePath, String trustKeyStorePath) throws Exception {
    
    
        // 初始化密钥库
        KeyManagerFactory keyManagerFactory = KeyManagerFactory
                .getInstance(SunX509);
        KeyStore keyStore = getKeyStore(keyStorePath, password);
        keyManagerFactory.init(keyStore, password.toCharArray());
 
        // 初始化信任库
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(SunX509);
        KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);
        trustManagerFactory.init(trustkeyStore);
 
        // 初始化SSL上下文
        SSLContext ctx = SSLContext.getInstance(SSL);
        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
                .getTrustManagers(), null);
        SSLSocketFactory sf = ctx.getSocketFactory();
 
        return sf;
    }
 
    /**
     * 为HttpsURLConnection配置SSLSocketFactory
     * 
     * @param conn
     *            HttpsURLConnection
     * @param password
     *            密码
     * @param keyStorePath
     *            密钥库路径
     * 
     * @param trustKeyStorePath
     *            信任库路径
     * @throws Exception
     */
    public static void configSSLSocketFactory(HttpsURLConnection conn,
            String password, String keyStorePath, String trustKeyStorePath)
            throws Exception {
    
    
        conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,
                trustKeyStorePath));
    }
}

The configSSLSocketFactory method is added for external calls, which configures SSLSocketFactory for HttpsURLConnection. When HttpsURLConnection is configured with SSLSocketFactory, we can use HttpURLConnection to operate as usual through getInputStream and getOutputStream of HttpsURLConnection. In particular, it should be noted that before SSLSocketFactory is configured, the value obtained by getContentLength() of HttpsURLConnection will always be **-1**.

Given the corresponding test class:

import static org.junit.Assert.*;
 
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;
 
import javax.net.ssl.HttpsURLConnection;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CertificateCoderTest {
    
    
    private String password = "123456";
    private String alias = "www.zlex.org";
    private String certificatePath = "d:/zlex.cer";
    private String keyStorePath = "d:/zlex.keystore";
    private String clientKeyStorePath = "d:/zlex-client.keystore";
    private String clientPassword = "654321";
 
    @Test
    public void test() throws Exception {
    
    
        System.err.println("公钥加密——私钥解密");
        String inputStr = "Ceritifcate";
        byte[] data = inputStr.getBytes();
 
        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
                certificatePath);
 
        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                keyStorePath, alias, password);
        String outputStr = new String(decrypt);
 
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
 
        // 验证数据一致
        assertArrayEquals(data, decrypt);
 
        // 验证证书有效
        assertTrue(CertificateCoder.verifyCertificate(certificatePath));
 
    }
 
    @Test
    public void testSign() throws Exception {
    
    
        System.err.println("私钥加密——公钥解密");
 
        String inputStr = "sign";
        byte[] data = inputStr.getBytes();
 
        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
                keyStorePath, alias, password);
 
        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                certificatePath);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
 
        System.err.println("私钥签名——公钥验证签名");
        // 产生签名
        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                password);
        System.err.println("签名:\r" + sign);
 
        // 验证签名
        boolean status = CertificateCoder.verify(encodedData, sign,
                certificatePath);
        System.err.println("状态:\r" + status);
        assertTrue(status);
 
    }
 
    @Test
    public void testHttps() throws Exception {
    
    
        URL url = new URL("https://www.zlex.org/examples/");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
        conn.setDoInput(true);
        conn.setDoOutput(true);
 
        CertificateCoder.configSSLSocketFactory(conn, clientPassword,
                clientKeyStorePath, clientKeyStorePath);
 
        InputStream is = conn.getInputStream();
 
        int length = conn.getContentLength();
 
        DataInputStream dis = new DataInputStream(is);
        byte[] data = new byte[length];
        dis.readFully(data);
 
        dis.close();
        System.err.println(new String(data));
        conn.disconnect();
    }
}

Pay attention to the testHttps method, which is almost the same as our usual HTTP access. Let's look at the console output:

<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>
<META http-equiv=Content-Type content="text/html">
</HEAD>
<BODY>
<P>
<H3>Apache Tomcat Examples</H3>
<P></P>
<ul>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/servlets">Servlets examples</a></li>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/jsp">JSP Examples</a></li>
</ul>
</BODY></HTML>

Visiting https://www.zlex.org/examples/ directly through the browser will also get the above content. That is to say, using Party A as the server to build the tomcat service, Party B can access Party A's protected SSL application through the above method, and does not need to consider specific encryption and decryption issues. Party A and Party B can configure effective SSL services through the tomcat of both parties through corresponding configuration, simplify the implementation of the above code, and complete SSL two-way authentication through certificate configuration!

We have done the authentication using a self-signed certificate. Next, we use a third-party CA signing authority to complete the certificate signing.
Here we use the 21-day free ca certificate provided by thawte for testing.
1. To indicate your domain name on this website, use www.zlex.org as the domain name for testing (do not use this domain name as your domain name address, this domain name is protected by law! Please use other non-registered domain names!) .
2. If the domain name is valid, you will receive an email asking you to visit https://www.thawte.com/cgi/server/try.exe to obtain a ca certificate.
3. Recite the creation of the keystore.

keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:\zlex.keystore

The password I use here is 123456

Console output:

输入keystore密码:
再次输入新密码:
您的名字与姓氏是什么?
  [Unknown]:  www.zlex.org
您的组织单位名称是什么?
  [Unknown]:  zlex
您的组织名称是什么?
  [Unknown]:  zlex
您所在的城市或区域名称是什么?
  [Unknown]BJ
您所在的州或省份名称是什么?
  [Unknown]BJ
该单位的两字母国家代码是什么
  [Unknown]CN
CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗?
  []Y

输入<tomcat>的主密码
        (如果和 keystore 密码相同,按回车):
再次输入新密码:

4. Use the following command to export the CA certificate application from zlex.keystore.

keytool -certreq -alias www.zlex.org -file d:\zlex.csr -keystore d:\zlex.keystore -v

You will get the zlex.csr file, which can be opened with Notepad, and the content is in the following format:

-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBnDCCAQUCAQAwXDELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMQswCQYDVQQHEwJCSjENMAsG
A1UEChMEemxleDENMAsGA1UECxMEemxleDEVMBMGA1UEAxMMd3d3LnpsZXgub3JnMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCR6DXU9Mp+mCKO7cv9JPsj0n1Ec/GpM09qvhpgX3FNad/ZWSDc
vU77YXZSoF9hQp3w1LC+eeKgd2MlVpXTvbVwBNVd2HiQPp37ic6BUUjSaX8LHtCl7l0BIEye9qQ2
j8G0kak7e8ZA0s7nb3Ymq/K8BV7v0MQIdhIc1bifK9ZDewIDAQABoAAwDQYJKoZIhvcNAQEFBQAD
gYEAMA1r2fbZPtNx37U9TRwadCH2TZZecwKJS/hskNm6ryPKIAp9APWwAyj8WJHRBz5SpZM4zmYO
oMCI8BcnY2A4JP+R7/SwXTdH/xcg7NVghd9A2SCgqMpF7KMfc5dE3iygdiPu+UhY200Dvpjx8gmJ
1UbH3+nqMUyCrZgURFslOUY=
-----END NEW CERTIFICATE REQUEST-----

5. Copy the content of the above file to https://www.thawte.com/cgi/server/try.exe, click next to get the response content, here is the p7b format.
The content is as follows:

-----BEGIN PKCS7-----
MIIF3AYJKoZIhvcNAQcCoIIFzTCCBckCAQExADALBgkqhkiG9w0BBwGgggWxMIID
EDCCAnmgAwIBAgIQA/mx/pKoaB+KGX2hveFU9zANBgkqhkiG9w0BAQUFADCBhzEL
MAkGA1UEBhMCWkExIjAgBgNVBAgTGUZPUiBURVNUSU5HIFBVUlBPU0VTIE9OTFkx
HTAbBgNVBAoTFFRoYXd0ZSBDZXJ0aWZpY2F0aW9uMRcwFQYDVQQLEw5URVNUIFRF
U1QgVEVTVDEcMBoGA1UEAxMTVGhhd3RlIFRlc3QgQ0EgUm9vdDAeFw0wOTA1Mjgw
MDIxMzlaFw0wOTA2MTgwMDIxMzlaMFwxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJC
SjELMAkGA1UEBxMCQkoxDTALBgNVBAoTBHpsZXgxDTALBgNVBAsTBHpsZXgxFTAT
BgNVBAMTDHd3dy56bGV4Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
keg11PTKfpgiju3L/ST7I9J9RHPxqTNPar4aYF9xTWnf2Vkg3L1O+2F2UqBfYUKd
8NSwvnnioHdjJVaV0721cATVXdh4kD6d+4nOgVFI0ml/Cx7Qpe5dASBMnvakNo/B
tJGpO3vGQNLO5292JqvyvAVe79DECHYSHNW4nyvWQ3sCAwEAAaOBpjCBozAMBgNV
HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBABgNVHR8E
OTA3MDWgM6Axhi9odHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNl
cnZlckNBLmNybDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9v
Y3NwLnRoYXd0ZS5jb20wDQYJKoZIhvcNAQEFBQADgYEATPuxZbtJJSPmXvfrr1yz
xqM06IwTZ6UU0lZRG7I0WufMjNMKdpn8hklUhE17mxAhGSpewLVVeLR7uzBLFkuC
X7wMXxhoYdJZtNai72izU6Rd1oknao7diahvRxPK4IuQ7y2oZ511/4T4vgY6iRAj
q4q76HhPJrVRL/sduaiu+gYwggKZMIICAqADAgECAgEAMA0GCSqGSIb3DQEBBAUA
MIGHMQswCQYDVQQGEwJaQTEiMCAGA1UECBMZRk9SIFRFU1RJTkcgUFVSUE9TRVMg
T05MWTEdMBsGA1UEChMUVGhhd3RlIENlcnRpZmljYXRpb24xFzAVBgNVBAsTDlRF
U1QgVEVTVCBURVNUMRwwGgYDVQQDExNUaGF3dGUgVGVzdCBDQSBSb290MB4XDTk2
MDgwMTAwMDAwMFoXDTIwMTIzMTIxNTk1OVowgYcxCzAJBgNVBAYTAlpBMSIwIAYD
VQQIExlGT1IgVEVTVElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQKExRUaGF3dGUg
Q2VydGlmaWNhdGlvbjEXMBUGA1UECxMOVEVTVCBURVNUIFRFU1QxHDAaBgNVBAMT
E1RoYXd0ZSBUZXN0IENBIFJvb3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
ALV9kG+Os6x/DOhm+tKUQfzVMWGhE95sFmEtkMMTX2Zi4n6i6BvzoReJ5njzt1LF
cqu4EUk9Ji20egKKfmqRzmQFLP7+1niSdfJEUE7cKY40QoI99270PTrLjJeaMcCl
+AYl+kD+RL5BtuKKU3PurYcsCsre6aTvjMcqpTJOGeSPAgMBAAGjEzARMA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAgozj7BkD9O8si2V0v+EZ/t7E
fz/LC8y6mD7IBUziHy5/53ymGAGLtyhXHvX+UIE6UWbHro3IqVkrmY5uC93Z2Wew
A/6edK3KFUcUikrLeewM7gmqsiASEKx2mKRKlu12jXyNS5tXrPWRDvUKtFC1uL9a
12rFAQS2BkIk7aU+ghYxAA==
-----END PKCS7-----

Store it as zlex.p7b
6. Import the certificate signed by the CA into the keystore.

keytool -import -trustcacerts -alias www.zlex.org -file d:\zlex.p7b -keystore d:\zlex.keystore -v

The password I use here is 123456

Console output:

输入keystore密码:

回复中的最高级认证:

所有者:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR
 TESTING PURPOSES ONLY, C=ZA
签发人:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR
 TESTING PURPOSES ONLY, C=ZA
序列号:0
有效期: Thu Aug 01 08:00:00 CST 1996Fri Jan 01 05:59:59 CST 2021
证书指纹:
         MD5:5E:E0:0E:1D:17:B7:CA:A5:7D:36:D6:02:DF:4D:26:A4
         SHA1:39:C6:9D:27:AF:DC:EB:47:D6:33:36:6A:B2:05:F1:47:A9:B4:DA:EA
         签名算法名称:MD5withRSA
         版本: 3

扩展:

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:2147483647
]


... 是不可信的。 还是要安装回复? []Y
认证回复已安装在 keystore中
[正在存储 d:\zlex.keystore]

7. Domain name positioning
Position the domain name www.zlex.org on this machine. Open the C:\Windows\System32\drivers\etc\hosts file and bind www.zlex.org to this machine. Append 127.0.0.1 www.zlex.org to the end of the file. Now visit http://www.zlex.org through the address bar, or through the ping command, if the machine can be located, the domain name mapping is done.

8. Configure server.xml

<Connector
			keystoreFile="conf/zlex.keystore"
			keystorePass="123456" 
			truststoreFile="conf/zlex.keystore"    
			truststorePass="123456"     
			SSLEnabled="true"
			URIEncoding="UTF-8"
			clientAuth="false"			
			maxThreads="150"
			port="443"
			protocol="HTTP/1.1"
			scheme="https"
			secure="true"
			sslProtocol="TLS" />

Copy the file zlex.keystore to the conf directory of tomcat , and restart tomcat. Visiting https://www.zlex.org/ we found the networking to be a bit sluggish. After about 5 seconds, the webpage is displayed normally, and at the same time, as shown in the figure below:
Various Java encryption algorithms
The browser has verified the validity of the CA organization.

Open the certificate, as shown in the following figure:
Various Java encryption algorithms

Adjust the test class:

import static org.junit.Assert.*;
 
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;
 
import javax.net.ssl.HttpsURLConnection;
 
import org.junit.Test;
 
/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CertificateCoderTest {
    
    
    private String password = "123456";
    private String alias = "www.zlex.org";
    private String certificatePath = "d:/zlex.cer";
    private String keyStorePath = "d:/zlex.keystore";
 
    @Test
    public void test() throws Exception {
    
    
        System.err.println("公钥加密——私钥解密");
        String inputStr = "Ceritifcate";
        byte[] data = inputStr.getBytes();
 
        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
                certificatePath);
 
        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                keyStorePath, alias, password);
        String outputStr = new String(decrypt);
 
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
 
        // 验证数据一致
        assertArrayEquals(data, decrypt);
 
        // 验证证书有效
        assertTrue(CertificateCoder.verifyCertificate(certificatePath));
 
    }
 
    @Test
    public void testSign() throws Exception {
    
    
        System.err.println("私钥加密——公钥解密");
 
        String inputStr = "sign";
        byte[] data = inputStr.getBytes();
 
        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
                keyStorePath, alias, password);
 
        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                certificatePath);
 
        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
 
        System.err.println("私钥签名——公钥验证签名");
        // 产生签名
        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                password);
        System.err.println("签名:\r" + sign);
 
        // 验证签名
        boolean status = CertificateCoder.verify(encodedData, sign,
                certificatePath);
        System.err.println("状态:\r" + status);
        assertTrue(status);
 
    }
 
    @Test
    public void testHttps() throws Exception {
    
    
        URL url = new URL("https://www.zlex.org/examples/");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
        conn.setDoInput(true);
        conn.setDoOutput(true);
 
        CertificateCoder.configSSLSocketFactory(conn, password, keyStorePath,
                keyStorePath);
 
        InputStream is = conn.getInputStream();
 
        int length = conn.getContentLength();
 
        DataInputStream dis = new DataInputStream(is);
        byte[] data = new byte[length];
        dis.readFully(data);
 
        dis.close();
        conn.disconnect();
        System.err.println(new String(data));
    }
}

Execute again, the verification is passed!
Thus, we realized the authentication process based on the SSL protocol. The testHttps method of the test class simulates a browser's HTTPS access.

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/132643396