返回介绍

加密算法实现

发布于 2024-09-08 15:42:05 字数 16450 浏览 0 评论 0 收藏 0

JDK

表格 16 Java 加密算法列表

算法简介import
BASE64属于编码格式,而非加密算法import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;
MD5Message Digest algorithm 5,信息摘要算法import java.math.BigInteger; import java.security.MessageDigest;
SHASecure Hash Algorithm,安全散列算法import java.math.BigInteger; import java.security.MessageDigest;
HMACHash 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 两种算法。

  1. 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 实现说明

  1. AES 理论上支持 128,192,256 三种长度的密钥,几乎全部密码块工作模式和填充方法,但 JDK 7 中只实现如下四种 AES 加密算法:
  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)
  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)

2.使用须知

  1. 缺省模式和填充为 AES/ECB/PKCS5Padding ,Cipher.getInstance ( AES ) 与 Cipher.getInstance ( AES/ECB/PKCS5Padding ) 等效。

  2. JDK 的 PKCS5Padding 实际是上述的 PKCS7 的实现。

  3. 由于 AES 是按照 16Byte 为块进行处理,对于 NoPadding 而言,如果需要加密的原文长度不是 16Byte 的倍数,将无法处理抛出异常,其实是由用户自己选择 Padding 的算法。密文则必然是 16Byte 的倍数,否则密文肯定异常。

  4. 如果加密为 PKCS5Padding,解密可以选择 NoPadding,也能解密成功,内容为原文加上 PKCS5Padding 之后的结果。

  5. 如果原文最后一个字符为>=0x00&&<=0x10 的内容,PKCS5Padding 的解密将会出现异常,要么是符 合 PKCS5Padding,最后的内容被删除,要么不符合,则解密失败抛出异常。对此有两种思路,一是原文通过 Base64 编码为可见字符,二是原文自 带长度使用 NoPadding 解密。

Java Cryptography Architecture Standard Algorithm Name Documentation

表格 17 Cipher Algorithm Names

Algorithm NameDescription
AESAdvanced 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.
AESWrapThe AES key wrapping algorithm as described in RFC 3394 .
ARCFOURA 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 .
BlowfishThe Blowfish block cipher designed by Bruce Schneier.
CCMCounter/CBC Mode, as defined in NIST Special Publication SP 800-38C .
DESThe Digital Encryption Standard as described in FIPS PUB 46-3 .
DESedeTriple 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.
DESedeWrapThe DESede key wrapping algorithm as described in RFC 3217 .
ECIESElliptic Curve Integrated Encryption Scheme
GCMGalois/Counter Mode, as defined in NIST Special Publication SP 800-38D .
PBEWith And PBEWith AndThe 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 .
RC2Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc.
RC4Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc. (See note prior for ARCFOUR.)
RC5Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc.
RSAThe RSA encryption algorithm as defined in PKCS #1

表格 18 Cipher Algorithm Modes

Algorithm NameDescription
NONENo mode.
CBCCipher Block Chaining Mode, as defined in FIPS PUB 81 .
CFB, CFBxCipher 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.
CTRA simplification of OFB, Counter mode updates the input block as a counter.
CTSCipher Text Stealing, as described in Bruce Schneier's book Applied Cryptography-Second Edition, John Wiley and Sons, 1996.
ECBElectronic Codebook Mode, as defined in FIPS PUB 81 (generally this mode should not be used for multiple blocks of data).
OFB, OFBxOutput 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.
PCBCPropagating Cipher Block Chaining, as defined by Kerberos V4 .

表格 19 Cipher Algorithm Padding

Algorithm NameDescription
NoPaddingNo padding.
ISO10126PaddingThis 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 PaddingOptimal 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.
PKCS1PaddingThe padding scheme described in PKCS #1 , used with the RSA algorithm.
PKCS5PaddingThe padding scheme described in RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, November 1993 .
SSL3PaddingThe 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文