foreword
Common encryption algorithms in programming are as follows, and they are used in different scenarios. In addition to the message digest algorithm, other encryption methods will require a key.
- Information Digest Algorithm
- Symmetric encryption algorithm
- Asymmetric encryption algorithm
key
key (Key, also often called key ) is used to refer to a complete encryption , decryption , integrity verification secret information such as cryptographic applications.
key classification
- Keys in encryption and decryption: The same key is shared in symmetric encryption. In asymmetric encryption, it is divided public key and private key , public key encryption and private key decryption.
- Keys in message authentication codes and digital signatures: In message authentication codes, the message sender and receiver use a shared secret key for authentication. In digital signature, the private key is used for signing and the public key is used for verification.
- Session key and master key: A key that is used only once per communication is called a session key. In contrast to the session key, the reused key is called the master key.
key and password
Passwords are generally generated by users, are readable, can be memorized and stored, and are often used for software management, while keys are used by software that implements encryption algorithms and do not need to be readable (but in programming, they are all done for ease of reading). Base64). We can also generate the key with a passphrase.
key management
- Generate key: You can use random numbers to generate keys, or you can use passwords to generate keys.
- Distribution key: It can use a shared key in advance, use a key distribution center, use public key cryptography, and use Diffie-Hellman key exchange.
- update key
- save key
- void key
key generation
jce (Java Cryptography Extension) in jdk includes all API related to encryption.
Generate the key for the symmetric encryption algorithm
public static SecretKey generateKey(int keySize) {
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(keySize);
return keyGenerator.generateKey();
} catch (NoSuchAlgorithmException e) {
// ignore
return null;
}
}
Generate key for symmetric asymmetric encryption algorithm
/**
* 生成非对称密钥对
*
* @param keySize 密钥大小
* @param random 指定随机来源,默认使用 JCAUtil.getSecureRandom()
* @return 非对称密钥对
* @throws NoSuchAlgorithmException NoSuchAlgorithm
*/
public static PPKeys genKeysRSA(int keySize, SecureRandom random) throws NoSuchAlgorithmException {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
if (null != random) {
generator.initialize(keySize, random);
} else {
generator.initialize(keySize);
}
KeyPair pair = generator.generateKeyPair();
PPKeys keys = new PPKeys();
PublicKey publicKey = pair.getPublic();
PrivateKey privateKey = pair.getPrivate();
keys.setPublicKey(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
keys.setPrivateKey(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
return keys;
}
Key Agreement ( Diffie-Hellman )
Key agreement is a protocol through which two or more parties establish the same shared key, and then the communication content is symmetrically encrypted and transmitted without exchanging keys.
Approximate process: each party generates a public-private key pair and distributes the public key to other parties, and the shared key can be calculated offline when both parties have obtained a copy of the other party's public key.
KeyAgreement
is provided in Java to implement key agreement.
- Alice and Bob respectively initialize their own key agreement object
KeyAgreement
with their private keys, and callinit()
method; - Then pass the public key of each party to the communication to execute
doPhase(Key key, boolean lastPhase)
; - The parties generate the shared key
generateSecret()
.
public static void diffieHellman() throws Exception {
AlgorithmParameterGenerator dhParams = AlgorithmParameterGenerator.getInstance("DH");
dhParams.init(1024);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(dhParams.generateParameters().getParameterSpec(DHParameterSpec.class), new SecureRandom());
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
KeyPair alicePair = keyGen.generateKeyPair();
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
KeyPair bobPair = keyGen.generateKeyPair();
aliceKeyAgree.init(alicePair.getPrivate());
bobKeyAgree.init(bobPair.getPrivate());
aliceKeyAgree.doPhase(bobPair.getPublic(), true);
bobKeyAgree.doPhase(alicePair.getPublic(), true);
boolean agree = Base64.getEncoder().encodeToString(aliceKeyAgree.generateSecret()).equals(
Base64.getEncoder().encodeToString(bobKeyAgree.generateSecret())
);
System.out.println(agree);
}
Information Digest Algorithm
The information digest algorithm is also called encryption hash algorithm . The encryption process does not require a key. Common encryption hash algorithms include MD series and SHA series .
An ideal cryptographic hash function should have the following properties:
- After any information is passed in, the output is always of a fixed length;
- The message digest appears "random", making it difficult to infer the value based on the raw information;
- The collision probability of a good hash function should be extremely low, that is, the probability of getting the same value after different information is passed in;
MD series
MD5 message digest algorithm (MD5 Message-Digest Algorithm), a widely used cryptographic hash function that outputs a 128-bit (16-byte) hash value, MD5 was originally designed as a cryptographic hash Column function, and it has been found to have a large number of loopholes, so it is not recommended to be used for encryption directly, but it is still widely used in non-encryption scenarios such as data integrity verification and file integrity verification.
public static String md5(String content) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(bytes);
} catch (final NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
}
SHA series
Secure Hash Algorithm (Secure Hash Algorithm, abbreviated as SHA) is a family of cryptographic hash functions and is a FIPS (Federal Information Processing Standard) certified secure hash algorithm. An algorithm that can calculate the fixed-length string (also called message digest) corresponding to a digital message. And if the input messages are different, there is a high probability that they correspond to different strings.
They respectively contain SHA-0、SHA-1、SHA-2、SHA-3
, of which the output length of SHA-0、SHA-1
is 160 bits, SHA-2
contains SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256
, and we usually use SHA-256
.
public static String sha256(String content) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256);
byte[] bytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(bytes);
} catch (final NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
}
Symmetric encryption algorithm
Symmetric encryption algorithm, both parties hold the same key for encryption and decryption, common symmetric encryption algorithm: DES
3DES
AES128
AES192
AES256
. To understand symmetric encryption, you need to understand the following concepts:
- block cipher mode : The plaintext is split and encrypted, and then the ciphertext is spliced together. For example, in AES, the plaintext data will be cut into data blocks of 16 bytes in size. When the last block is not enough to 16 bytes, the Padding mode is used to supplement it.
- padding (Padding) : It has three modes PKCS5, PKCS7 and NOPADDING, PKCS5 is filled with the number of missing bytes, for example, if 5 bytes are missing, 5 numbers are filled, and the number of missing bytes in PKCS7 is filled with 0 . If the data is an integer multiple of 16, PKCS5 and PKCS7 will add another 16 bytes of data to distinguish padding and valid data, and NOPADDING mode does not require padding.
- initialization vector : The role of the initial vector IV is to make encryption more secure and reliable. In block cipher mode, the IV size corresponds to the length of the data block.
- encryption mode : The four encryption modes are: ECB (electronic codebook mode), CBC (cipher block chain mode), CFB, OFB. ECB mode only uses plaintext and key to encrypt data, so padding is not required in this mode, and the security is also weak. Therefore, CBC mode is generally selected at present.
- encryption key : Different encryption algorithms have different key lengths, for example: DES has a default length of 56 bits, 3DES has a default length of 168 bits, and also supports 128 bits, AES defaults to 128 bits, and also supports 192 bits and 256 bits. We generally generate keys based on passwords, and the password length needs to meet the algorithm key length.
DES
DES
is a typical algorithm in the field of symmetric encryption algorithms, because the default key length is 56 bit
, so the password length needs to be greater than 8 byte
, and DESKeySpec
takes the first 8 byte
for key generation.
public static String encryptDES(byte[] content, String password) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, random);
return Base64.getEncoder().encodeToString(cipher.doFinal(content));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String decryptDES(String content, String password) throws Exception {
SecureRandom random = new SecureRandom();
DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey, random);
return new String(cipher.doFinal(Base64.getDecoder().decode(content)));
}
3DES
3DES (ie Triple DES). It is an enhancement of the DES algorithm, which uses three 56-bit keys to encrypt data three times. It takes DES as the basic module, and designs the block encryption algorithm by combining the grouping method. 3DES is more secure than the original DES. The default key length is 168 bit
, the password needs to be greater than 24 byte
, and the IV is an array of random numbers and letters of 8 byte
.
public static String encrypt3DESECB(String content, String key, String iv) {
try {
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
DESedeKeySpec dks = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey secretkey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretkey, ivSpec);
return Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String decrypt3DESECB(String content, String key, String iv) {
try {
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
DESedeKeySpec dks = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey secretkey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretkey, ivSpec);
return new String(cipher.doFinal(Base64.getDecoder().decode(content)), StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
AES
AES is an advanced data encryption standard, which can effectively resist all known attacks against the DES algorithm. The default key length is 128 bit
, and 192 bit
and 256 bit
can also be selected. AES-128
AES-192
AES-256
Default AES-128
, use PBEKeySpec
to generate a fixed size key.
public static String encryptAES128(String plainText, String password, String salt) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8);
// AES-128 密钥长度为128bit
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
1000,
128
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AlgorithmParameters params = cipher.getParameters();
IvParameterSpec iv = params.getParameterSpec(IvParameterSpec.class);
cipher.init(Cipher.ENCRYPT_MODE, secret, iv);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
String encodedText = Base64.getEncoder().encodeToString(encryptedTextBytes);
String encodedIV = Base64.getEncoder().encodeToString(iv.getIV());
String encodedSalt = Base64.getEncoder().encodeToString(saltBytes);
return encodedSalt + "." + encodedIV + "." + encodedText;
}
public static String decryptAES128(String encryptedText, String password) throws Exception {
String[] fields = encryptedText.split("\\.");
byte[] saltBytes = Base64.getDecoder().decode(fields[0]);
byte[] ivBytes = Base64.getDecoder().decode(fields[1]);
byte[] encryptedTextBytes = Base64.getDecoder().decode(fields[2]);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
1000,
128
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException(e);
}
}
The following exception may occur when using AES-256
:
java.security.InvalidKeyException: Illegal key size
JDK 1.8.0_161 and above have unlimited strength encryption enabled by default:
static {
java.security.Security.setProperty("crypto.policy", "unlimited");
}
Versions prior to JDK 1.8.0_161 need to manually install jce policy file ( download address )
Asymmetric encryption algorithm
Asymmetric encryption uses a pair of keys, the public key is used for encryption and the private key is used for decryption. Regarding key size, as of 2020, the largest publicly known RSA key is 829-bit RSA-250, and at least a 2048-bit key is recommended.
public static String encrypt(byte[] publicKey, String plainText) {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf;
try {
kf = KeyFactory.getInstance("RSA");
PublicKey publicKeySecret = kf.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKeySecret);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
return new String(Base64.getEncoder().encode(encryptedBytes));
} catch (Exception e) {
log.error("Rsa encrypt error ", e);
throw new RuntimeException(e);
}
}
public static String decrypt(byte[] privateKey, String encryptedText) {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf;
try {
kf = KeyFactory.getInstance("RSA");
PrivateKey privateKeySecret = kf.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKeySecret);
return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedText)), StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("Rsa decrypt error ", e);
throw new RuntimeException(e);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。