加密算法实现
JDK
表格 16 Java 加密算法列表
算法 | 简介 | import |
---|---|---|
BASE64 | 属于编码格式,而非加密算法 | import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; |
MD5 | Message Digest algorithm 5,信息摘要算法 | import java.math.BigInteger; import java.security.MessageDigest; |
SHA | Secure Hash Algorithm,安全散列算法 | import java.math.BigInteger; import java.security.MessageDigest; |
HMAC | Hash Message Authentication Code,散列消息鉴别码,基于密钥的 Hash 算法的认证协议 。 | import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; |
AES | import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; | |
RSA |
备注:1. JDK 6 提供实现了 DH 和 RSA 两种算法。
- JDK 7 实现四种 AES 加密算法分别是 CBC 和 ECB 各两种。
JDK AES 代码示例如下 :
// Java SDK: javax.crypto.Cipher
// JDK 中 AES 缺省实现为: AES/ECB/PKCS5Padding
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesECB {
public static byte[] Encrypt(byte[] text, byte[] key) throws Exception {
SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // default, same as "AES"
// Cipher cipher = Cipher.getInstance("AES"); // same as above
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
return cipher.doFinal(text);
}
public static byte[] Decrypt(byte[] text, byte[] key) throws Exception {
SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
return cipher.doFinal(text);
}
public static String bytes2hex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String temp = (Integer.toHexString(bytes[i] & 0XFF));
if (temp.length() == 1) {
temp = "0" + temp;
}
sb.append(temp);
sb.append(" ");
}
return sb.toString().toUpperCase();
}
public static void main(String[] args) {
try {
String key = args[0];
String text = args[1];
System.out.printf("text : %s\n", bytes2hex(text.getBytes()));
byte[] enc = AesECB.Encrypt(text.getBytes(), key.getBytes());
System.out.printf("encrypt: %s\n", bytes2hex(enc));
byte[] dec = AesECB.Decrypt(enc, key.getBytes());
System.out.printf("decrypt: %s\n", bytes2hex(dec));
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDK AES 实现说明
- AES 理论上支持 128,192,256 三种长度的密钥,几乎全部密码块工作模式和填充方法,但 JDK 7 中只实现如下四种 AES 加密算法:
- AES/CBC/NoPadding (128)
- AES/CBC/PKCS5Padding (128)
- AES/ECB/NoPadding (128)
- AES/ECB/PKCS5Padding (128)
2.使用须知
缺省模式和填充为
AES/ECB/PKCS5Padding
,Cipher.getInstance (AES
) 与 Cipher.getInstance (AES/ECB/PKCS5Padding
) 等效。JDK 的 PKCS5Padding 实际是上述的 PKCS7 的实现。
由于 AES 是按照 16Byte 为块进行处理,对于 NoPadding 而言,如果需要加密的原文长度不是 16Byte 的倍数,将无法处理抛出异常,其实是由用户自己选择 Padding 的算法。密文则必然是 16Byte 的倍数,否则密文肯定异常。
如果加密为 PKCS5Padding,解密可以选择 NoPadding,也能解密成功,内容为原文加上 PKCS5Padding 之后的结果。
如果原文最后一个字符为>=0x00&&<=0x10 的内容,PKCS5Padding 的解密将会出现异常,要么是符 合 PKCS5Padding,最后的内容被删除,要么不符合,则解密失败抛出异常。对此有两种思路,一是原文通过 Base64 编码为可见字符,二是原文自 带长度使用 NoPadding 解密。
Java Cryptography Architecture Standard Algorithm Name Documentation
表格 17 Cipher Algorithm Names
Algorithm Name | Description |
---|---|
AES | Advanced Encryption Standard as specified by NIST in FIPS 197 . Also known as the Rijndael algorithm by Joan Daemen and Vincent Rijmen, AES is a 128-bit block cipher supporting keys of 128, 192, and 256 bits. |
AESWrap | The AES key wrapping algorithm as described in RFC 3394 . |
ARCFOUR | A stream cipher believed to be fully interoperable with the RC4 cipher developed by Ron Rivest. For more information, see K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm 'Arcfour'", Internet Draft (expired), draft-kaukonen-cipher-arcfour-03.txt . |
Blowfish | The Blowfish block cipher designed by Bruce Schneier. |
CCM | Counter/CBC Mode, as defined in NIST Special Publication SP 800-38C . |
DES | The Digital Encryption Standard as described in FIPS PUB 46-3 . |
DESede | Triple DES Encryption (also known as DES-EDE, 3DES, or Triple-DES). Data is encrypted using the DES algorithm three separate times. It is first encrypted using the first subkey, then decrypted with the second subkey, and encrypted with the third subkey. |
DESedeWrap | The DESede key wrapping algorithm as described in RFC 3217 . |
ECIES | Elliptic Curve Integrated Encryption Scheme |
GCM | Galois/Counter Mode, as defined in NIST Special Publication SP 800-38D . |
PBEWith And PBEWith And | The password-based encryption algorithm found in (PKCS5), using the specified message digest () or pseudo-random function () and encryption algorithm (). Examples: PBEWithMD5AndDES: The password-based encryption algorithm as defined in RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, Nov 1993 . Note that this algorithm implies CBC as the cipher mode and PKCS5Padding as the padding scheme and cannot be used with any other cipher modes or padding schemes. PBEWithHmacSHA256AndAES_128: The password-based encryption algorithm as defined in RSA Laboratories, "PKCS #5: Password-Based Cryptography Standard," version 2.0, March 1999 . |
RC2 | Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc. |
RC4 | Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc. (See note prior for ARCFOUR.) |
RC5 | Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc. |
RSA | The RSA encryption algorithm as defined in PKCS #1 |
表格 18 Cipher Algorithm Modes
Algorithm Name | Description |
---|---|
NONE | No mode. |
CBC | Cipher Block Chaining Mode, as defined in FIPS PUB 81 . |
CFB, CFBx | Cipher Feedback Mode, as defined in FIPS PUB 81 . Using modes such as CFB and OFB, block ciphers can encrypt data in units smaller than the cipher's actual block size. When requesting such a mode, you may optionally specify the number of bits to be processed at a time by appending this number to the mode name as shown in the "DES/CFB8/NoPadding" and "DES/OFB32/PKCS5Padding" transformations. If no such number is specified, a provider-specific default is used. (For example, the SunJCE provider uses a default of 64 bits for DES.) Thus, block ciphers can be turned into byte-oriented stream ciphers by using an 8-bit mode such as CFB8 or OFB8. |
CTR | A simplification of OFB, Counter mode updates the input block as a counter. |
CTS | Cipher Text Stealing, as described in Bruce Schneier's book Applied Cryptography-Second Edition, John Wiley and Sons, 1996. |
ECB | Electronic Codebook Mode, as defined in FIPS PUB 81 (generally this mode should not be used for multiple blocks of data). |
OFB, OFBx | Output Feedback Mode, as defined in FIPS PUB 81 . Using modes such as CFB and OFB, block ciphers can encrypt data in units smaller than the cipher's actual block size. When requesting such a mode, you may optionally specify the number of bits to be processed at a time by appending this number to the mode name as shown in the "DES/CFB8/NoPadding" and "DES/OFB32/PKCS5Padding" transformations. If no such number is specified, a provider-specific default is used. (For example, the SunJCE provider uses a default of 64 bits for DES.) Thus, block ciphers can be turned into byte-oriented stream ciphers by using an 8-bit mode such as CFB8 or OFB8. |
PCBC | Propagating Cipher Block Chaining, as defined by Kerberos V4 . |
表格 19 Cipher Algorithm Padding
Algorithm Name | Description |
---|---|
NoPadding | No padding. |
ISO10126Padding | This padding for block ciphers is described in 5.2 Block Encryption Algorithms in the W3C's "XML Encryption Syntax and Processing" document. |
OAEPPadding, OAEPWith And Padding | Optimal Asymmetric Encryption Padding scheme defined in PKCS1, where should be replaced by the message digest and by the mask generation function. Examples: OAEPWithMD5AndMGF1Padding and OAEPWithSHA-512AndMGF1Padding. If OAEPPadding is used, Cipher objects are initialized with a javax.crypto.spec.OAEPParameterSpec object to supply values needed for OAEPPadding. |
PKCS1Padding | The padding scheme described in PKCS #1 , used with the RSA algorithm. |
PKCS5Padding | The padding scheme described in RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, November 1993 . |
SSL3Padding | The padding scheme defined in the SSL Protocol Version 3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher): . <br/>block-ciphered struct { <br/>opaque content[SSLCompressed.length]; <br/>opaque MAC[CipherSpec.hash_size]; <br/>uint8 padding[ GenericBlockCipher.padding_length]; uint8 padding_length; } <br/>GenericBlockCipher; The size of an instance of a GenericBlockCipher must be a multiple of the block cipher's block length. <br/>The padding length, which is always present, <br/>contributes to the padding, which implies that if: sizeof(content) + sizeof(MAC) % block_length = 0, padding has to be (block_length - 1) bytes long, because of the existence of padding_length. <br/>This makes the padding scheme similar (but not quite) to PKCS5Padding, where the padding length is encoded in the padding (and ranges from 1 to block_length). With the SSL scheme, the sizeof(padding) is encoded in the always present padding_length and therefore ranges from 0 to block_length-1<br/> |
AES 跨平台实现
加密模式: ECB,CBC,CFB,OFB,CTR,XTS…
密钥长度: 128, 256
iv 向量(init vector): 需要与密钥同时设置。初始化向量,提升了解密复杂度。
padding: NoPadding,ZeroPadding,PKCS5Padding,ISO10126Padding,ANSI X.923,SSL3Padding…
密钥: 用于加解密的 key
Java 版
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesTest {
/**
* 加密用的 Key 可以用 26 个字母和数字组成
* 此处使用 AES-128-CBC 加密模式,key 需要为 16 位。
*/
private static String sKey = "16bits";
private static String ivParameter = "1234567890123456";
// 加密
public static String encrypt(String sSrc) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] raw = sKey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//使用 CBC 模式,需要一个向量 iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
return new BASE64Encoder().encode(encrypted);//此处使用 BASE64 做转码。
}
// 解密
public static String decrypt(String sSrc) {
try {
byte[] raw = sKey.getBytes("ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用 base64 解密
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original, "utf-8");
return originalString;
} catch (Exception ex) {
return null;
}
}
public static void main(String[] args) {
String email = "lingyejun@java.aes";
try {
String sec = encrypt(email);
System.out.println(sec);
System.out.println(decrypt("CcOtM9WXv0N+Owh/xxedZJnuNUaTU7y3aUBESQLUvVM="));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Python 版
import base64
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
DEFAULT_ENCODING = 'utf-8'
class AESEncrypt:
def __init__(self, key=b"bnnw1234@datalab", iv=b"NIfb&95GUY86Gfgh"):
self.key = key
self.iv = iv # 初始化向量,提高解密复杂度
self.mode = AES.MODE_CBC
self.ENCODING = DEFAULT_ENCODING
@staticmethod
def padding(text, block_size=AES.block_size):
"""
补位
@param text: string
@param block_size:
@return: string
"""
count = len(text.encode(DEFAULT_ENCODING))
add = 0 if count % block_size == 0 else block_size - (count % block_size)
text1 = text + ('\0' * add)
return text1
def encrypt(self, text):
"""
加密:需补位,再加密,再 base64 编辑
@text: string
@return: string
"""
cryptor = AES.new(self.key, self.mode, self.iv)
text_pad = self.padding(text)
ciphertext = cryptor.encrypt(text_pad.encode(self.ENCODING))
cryptedStr = str(base64.b64encode(ciphertext), encoding=self.ENCODING)
return cryptedStr
def decrypt(self, text):
"""
解密 b64decode=decodebytes
@param text: string
@return:
"""
base_text = base64.b64decode(text.encode(self.ENCODING))
cryptor = AES.new(self.key, self.mode, self.iv)
plain_text = cryptor.decrypt(base_text)
text_decrypted = plain_text.decode(self.ENCODING).rstrip('\0')
return text_decrypted
if __name__ == '__main__':
str2 = "1234"
aes_obj = AESEncrypt()
e2 = aes_obj.encrypt(str2)
print(e2, aes_obj.decrypt(e2))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论