package com.bosd.GansuLogistics.UI; import android.text.TextUtils; import android.util.Base64;import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;public class LoginActivity extends FullscreenTransparentStatusBarActivity {public final static String MD5(String s) { try { byte[] btInput = s.getBytes(); MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(btInput); byte[] md = md5.digest(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < md.length; i++) { int val = md[i] & 0xff; if (val < 16) sb.append("0"); sb.append(Integer.toHexString(val)); } return sb.toString(); } catch (Exception e) { return null; } } private static final String KEY_ALGORITHM = "AES"; public static String encrypt(String content, String secretKey, String ivp) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getBytes(), KEY_ALGORITHM), new IvParameterSpec(ivp.getBytes())); return Base64.encodeToString(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)),Base64.NO_WRAP); } public static String encrypt2(String content, String key, String iv) { try { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");// 创建密码器 int blockSize = cipher.getBlockSize(); byte[] byteContent = content.getBytes(); int plaintextLength = byteContent.length; if (plaintextLength % blockSize != 0) { plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); } byte[] plaintext = new byte[plaintextLength]; System.arraycopy(byteContent, 0, plaintext, 0, byteContent.length); cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key), new IvParameterSpec(iv.getBytes()));// 初始化为加密模式的密码器 String a = Base64.encodeToString(cipher.doFinal(plaintext), Base64.NO_WRAP); return a; } catch (Exception ex) { ex.printStackTrace(); } return null; } private static SecretKeySpec getSecretKey(final String password) { int len = password.getBytes().length; if (len % 16 != 0) { len = len + (16 - (len % 16)); } byte[] newpass = new byte[len]; System.arraycopy(password.getBytes(), 0, newpass, 0, password.getBytes().length); return new SecretKeySpec(newpass, "AES"); } @Override protected void onCreate(Bundle savedInstanceState) { // 企业ID String company_id = "dd12503f07c04dbabab005112d99eaad"; // 企业密码 String secret = "wI0QCgnXLPy1ymmouYsHdCnt2rYFMIsgtHesJiw5+MY="; String timestamp = MessageFormat.format("{0,number}",System.currentTimeMillis()); timestamp = "1670213042710"; String KEY = "huasu20201114api"; String IV = "huasu20201114api"; System.out.println(timestamp); //MD5 加密一次 String md5_Str = MD5(company_id+secret); System.out.println(md5_Str); //AES 加密一次 String accessToken = null; try { //accessToken = encrypt(md5_Str+timestamp,KEY, IV); accessToken = encrypt2(md5_Str + timestamp, KEY, IV); System.out.println(accessToken); } catch (Exception e) { e.printStackTrace(); }
Java AES加密如何使用zeropadding方式填充
OrangeJack
已于 2022-08-26 11:44:47 修改
23475
收藏 17
文章标签: Java AES 加密
版权
前一久,在对接支付通道时,遇到上游使用AES加密方式,对方要求加密时使用CBC模式,zeropadding填充,偏移量为0000*4(即16个0),输出十六进制,字符集使用UTF-8。
本以为也没什么问题,可到实际开发时却发现Java虽然支持AES的CBC模式,但填充方式却没有zeropadding模式。通过查看文档,先梳理一下加密算法相关的知识。
JDK1.8支持的加密算法:
Cipher Algorithm Names
The following names can be specified as the algorithm component in a transformation when requesting an instance of Cipher.
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.
To use the AES cipher with only one valid key size, use the format AES_<n>, where <n> can be 128, 192, or 256.
AESWrap
The AES key wrapping algorithm as described in RFC 3394.
To use the AESWrap cipher with only one valid key size, use the format AESWrap_<n>, where <n> can be 128, 192, or 256.
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.
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
PBEWith<digest>And<encryption> PBEWith<prf>And<encryption> The password-based encryption algorithm found in (PKCS5), using the specified message digest (<digest>) or pseudo-random function (<prf>) and encryption algorithm (<encryption>). 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, September 2000 .
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
支持的加密算法模式:
Cipher Algorithm Modes
The following names can be specified as the mode component in a transformation when requesting an instance of Cipher.
Algorithm Name Description
NONE No mode.
CBC Cipher Block Chaining Mode, as defined in FIPS PUB 81.
CCM Counter/CBC Mode, as defined in NIST Special Publication SP 800-38C.
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).
GCM Galois/Counter Mode, as defined in NIST Special Publication SP 800-38D.
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.
这里简单说一下加密算法模式,不要把它与加密算法混淆起来,加密算法就是使用何种方式加密,比如:DES、AES、RSA,而加密算法模式,是用来描述加密算法(此处特指分组密码,不包括流密码,)在加密时对明文分组的模式,它代表了不同的分组方式,如常见的:
ECB模式:电子密码本模式
CBC模式:密码分组连接模式
CFB模式:密文反馈模式
OFB模式:输出反馈模式
CTR模式:计数器模式
感兴趣的童鞋可以自行查找资料研究。
支持的加密算法填充方式:
Cipher Algorithm Padding
The following names can be specified as the padding component in a transformation when requesting an instance of Cipher.
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<digest>And<mgf>Padding Optimal Asymmetric Encryption Padding scheme defined in PKCS1, where <digest> should be replaced by the message digest and <mgf> 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):
block-ciphered struct {
opaque content[SSLCompressed.length];
opaque MAC[CipherSpec.hash_size];
uint8 padding[
GenericBlockCipher.padding_length];
uint8 padding_length;
} GenericBlockCipher;
The size of an instance of a GenericBlockCipher must be a multiple of the block cipher's block length.
The padding length, which is always present, 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.
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.
说一下什么是填充方式,填充方式是在分组密码中,当明文长度不是分组长度的整数倍时,需要在最后一个分组中填充一些数据使其凑满一个分组的长度。
看到这,发现根本没有对方要求的zeropadding填充方式,那咋整?还有偏移量是什么鬼?此处。。。。烦躁
最后,查找到一个类似的案例解决了此问题,事后也查了下相关资料,现在先来回答上面两个问题,之后贴出代码。
一、zeropadding填充方式,它是使用“0”作为填充数据的填充方式,也就是说在分组时,最后一组明文的长度没有达到分组长度,那么就用“0”来补足。.Net 平台提供了这种方式,但Java没有提供,但Java提供NoPadding这中方式,意思是不做填充,这肯定不行,那怎么办?其实要的就是你不填充,这样我才能自己填充,我想填什么就填什么,如何填充呢?
二、偏移量,也叫初始化向量(IV),这个概念涉及到CBC模式的原理,那就顺便说一下,方便大家理解,CBC模式在对明文分组加密时,会将明文分组与前一个密文分组进行XOR运算(即异或运算),但是加密第一个明文分组时不存在“前一个密文分组”,因此需要事先准备一个与分组长度相等的比特序列来代替,这个比特序列就是偏移量。
好了,明白这了这两个概念,那么下面就是根据zeropadding填充规则和对方要求的偏移量来自己用代码实现了,直接上代码
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESEncrypt {
public static String encrypt(String data, String key) {
// 偏移量
String ivString = "0000000000000000";
byte[] iv = ivString.getBytes();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int length = dataBytes.length;
// 计算需填充长度
if (length % blockSize != 0) {
length = length + (blockSize - (length % blockSize));
}
byte[] plaintext = new byte[length];
// 填充
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
// 设置偏移量参数
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encryped = cipher.doFinal(plaintext);
return parseByte2HexStr(encryped);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static String desEncrypt(String data, String key) {
String ivString = "0000000000000000";
byte[] iv = ivString.getBytes();
try {
byte[] encryp = parseHexStr2Byte(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] original = cipher.doFinal(encryp);
return new String(original);
} catch (Exception e) {
// TODO: handle exception
}
return null;
}
public static String parseByte2HexStr(byte[] buf) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; ++i) {
String hex = Integer.toHexString(buf[i] & 255);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) {
return null;
} else {
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; ++i) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
public static void main(String[] args) {
String data = "123456";
String key = "186751244B391A6DCA84778E0D6A8910";
String encrypt = encrypt(data, key);
System.out.println("加密前:" + data);
System.out.println("加密后:" + encrypt);
String desEncrypt = desEncrypt(encrypt, key);
System.out.println("解密后:" + desEncrypt);
}
}
南来地,北往的,上班的,下岗的,走过路过不要错过!
======================个性签名=====================
之前认为Apple 的iOS 设计的要比 Android 稳定,我错了吗?
下载的许多客户端程序/游戏程序,经常会Crash,是程序写的不好(内存泄漏?刚启动也会吗?)还是iOS本身的不稳定!!!
如果在Android手机中可以简单联接到ddms,就可以查看系统log,很容易看到程序为什么出错,在iPhone中如何得知呢?试试Organizer吧,分析一下Device logs,也许有用.