我想关于AES算法大家应该都已经了解了,我就不多介绍了。这是本人第一次写技术博文,如果有不对之处欢迎大家指正,共同讨论,一起学习!
之前在项目上用到AES256加密解密算法,刚开始在java端加密解密都没有问题,在iOS端加密解密也没有问题。但是奇怪的是在java端加密后的文件在iOS端无法正确解密打开,然后简单测试了一下,发现在java端和iOS端采用相同明文,相同密钥加密后的密文不一样!上网查了资料后发现iOS中AES加密算法采用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我们知道加密算法由算法+模式+填充组成,所以这两者不同的填充算法导致相同明文相同密钥加密后出现密文不一致的情况。那么我们需要在java中用PKCS7Padding来填充,这样就可以和iOS端填充算法一致了。
要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现,下面我会提供该包的下载。啰嗦了一大堆,下面是一个简单的测试,上代码!
001 | package com.encrypt.file; |
004 | import java.io.UnsupportedEncodingException; |
005 | import java.security.Key; |
006 | import java.security.Security; |
008 | import javax.crypto.Cipher; |
009 | import javax.crypto.SecretKey; |
010 | import javax.crypto.spec.SecretKeySpec; |
012 | public class AES256Encryption{ |
016 | * java6支持56位密钥,bouncycastle支持64位 |
018 | public static final String KEY_ALGORITHM= "AES" ; |
023 | * JAVA6 支持PKCS5PADDING填充方式 |
024 | * Bouncy castle支持PKCS7Padding填充方式 |
026 | public static final String CIPHER_ALGORITHM= "AES/ECB/PKCS7Padding" ; |
030 | * 生成密钥,java6只支持56位密钥,bouncycastle支持64位密钥 |
031 | * @return byte[] 二进制密钥 |
033 | public static byte [] initkey() throws Exception{ |
046 | return new byte [] { 0x08 , 0x08 , 0x04 , 0x0b , 0x02 , 0x0f , 0x0b , 0x0c , |
047 | 0x01 , 0x03 , 0x09 , 0x07 , 0x0c , 0x03 , 0x07 , 0x0a , 0x04 , 0x0f , |
048 | 0x06 , 0x0f , 0x0e , 0x09 , 0x05 , 0x01 , 0x0a , 0x0a , 0x01 , 0x09 , |
049 | 0x06 , 0x07 , 0x09 , 0x0d }; |
057 | public static Key toKey( byte [] key) throws Exception{ |
060 | SecretKey secretKey= new SecretKeySpec(key,KEY_ALGORITHM); |
068 | * @return byte[] 加密后的数据 |
070 | public static byte [] encrypt( byte [] data, byte [] key) throws Exception{ |
075 | * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 |
076 | * Cipher.getInstance(CIPHER_ALGORITHM,"BC") |
078 | Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider()); |
079 | Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC" ); |
081 | cipher.init(Cipher.ENCRYPT_MODE, k); |
083 | return cipher.doFinal(data); |
089 | * @return byte[] 解密后的数据 |
091 | public static byte [] decrypt( byte [] data, byte [] key) throws Exception{ |
096 | * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 |
097 | * Cipher.getInstance(CIPHER_ALGORITHM,"BC") |
099 | Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM); |
101 | cipher.init(Cipher.DECRYPT_MODE, k); |
103 | return cipher.doFinal(data); |
107 | * @throws UnsupportedEncodingException |
110 | public static void main(String[] args) throws UnsupportedEncodingException{ |
113 | System.out.println( "原文:" +str); |
118 | key = AES256Encryption.initkey(); |
119 | System.out.print( "密钥:" ); |
120 | for ( int i = 0 ;i<key.length;i++){ |
121 | System.out.printf( "%x" , key[i]); |
123 | System.out.print( "\n" ); |
125 | byte [] data=AES256Encryption.encrypt(str.getBytes(), key); |
126 | System.out.print( "加密后:" ); |
127 | for ( int i = 0 ;i<data.length;i++){ |
128 | System.out.printf( "%x" , data[i]); |
130 | System.out.print( "\n" ); |
133 | data=AES256Encryption.decrypt(data, key); |
134 | System.out.println( "解密后:" + new String(data)); |
135 | } catch (Exception e) { |
运行程序后的结果截图:
上图可以看到密钥和密文,好了,我们来看看iOS端实现AES256加密解密的方法,有点复杂,大家耐心点看就好。
EncryptAndDecrypt.h文件
09 | #import <Foundation/Foundation.h> |
13 | @interface NSData (Encryption) |
15 | - (NSData *)AES256EncryptWithKey:(NSData *)key; |
16 | - (NSData *)AES256DecryptWithKey:(NSData *)key; |
17 | - (NSString *)newStringInBase64FromData; |
18 | + (NSString*)base64encode:(NSString*)str; |
EncryptAndDecrypt.m文件
009 | #import "EncryptAndDecrypt.h" |
010 | #import <CommonCrypto/CommonCrypto.h> |
011 | static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; |
013 | @implementation NSData (Encryption) |
015 | - (NSData *)AES256EncryptWithKey:(NSData *)key |
019 | const void * keyPtr2 = [key bytes]; |
020 | char (*keyPtr)[32] = keyPtr2; |
024 | NSUInteger dataLength = [self length]; |
025 | size_t bufferSize = dataLength + kCCBlockSizeAES128; |
026 | void *buffer = malloc (bufferSize); |
028 | size_t numBytesEncrypted = 0; |
029 | CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, |
030 | kCCOptionPKCS7Padding | kCCOptionECBMode, |
031 | [key bytes], kCCKeySizeAES256, |
033 | [self bytes], dataLength, |
037 | if (cryptStatus == kCCSuccess) { |
038 | return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; |
045 | - (NSData *)AES256DecryptWithKey:(NSData *)key |
049 | const void * keyPtr2 = [key bytes]; |
050 | char (*keyPtr)[32] = keyPtr2; |
054 | NSUInteger dataLength = [self length]; |
055 | size_t bufferSize = dataLength + kCCBlockSizeAES128; |
056 | void *buffer = malloc (bufferSize); |
058 | size_t numBytesDecrypted = 0; |
059 | CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, |
060 | kCCOptionPKCS7Padding | kCCOptionECBMode, |
061 | keyPtr, kCCKeySizeAES256, |
063 | [self bytes], dataLength, |
066 | if (cryptStatus == kCCSuccess) { |
067 | return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; |
074 | - (NSString *)newStringInBase64FromData |
076 | NSMutableString *dest = [[NSMutableString alloc] initWithString:@ "" ]; |
077 | unsigned char * working = (unsigned char *)[self bytes]; |
078 | int srcLen = [self length]; |
079 | for ( int i=0; i<srcLen; i += 3) { |
080 | for ( int nib=0; nib<4; nib++) { |
081 | int byt = (nib == 0)?0:nib-1; |
083 | if (i+byt >= srcLen) break ; |
084 | unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F); |
085 | if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F); |
086 | [dest appendFormat:@ "%c" , base64[curr]]; |
092 | + (NSString*)base64encode:(NSString*)str |
094 | if ([str length] == 0) |
096 | const char *source = [str UTF8String]; |
097 | int strlength = strlen (source); |
098 | char *characters = malloc (((strlength + 2) / 3) * 4); |
099 | if (characters == NULL) |
101 | NSUInteger length = 0; |
103 | while (i < strlength) { |
104 | char buffer[3] = {0,0,0}; |
105 | short bufferLength = 0; |
106 | while (bufferLength < 3 && i < strlength) |
107 | buffer[bufferLength++] = source[i++]; |
108 | characters[length++] = base64[(buffer[0] & 0xFC) >> 2]; |
109 | characters[length++] = base64[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)]; |
110 | if (bufferLength > 1) |
111 | characters[length++] = base64[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)]; |
112 | else characters[length++] = '=' ; |
113 | if (bufferLength > 2) |
114 | characters[length++] = base64[buffer[2] & 0x3F]; |
115 | else characters[length++] = '=' ; |
117 | NSString *g = [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES]; |
ViewController.m文件
09 | #import "ViewController.h" |
10 | #import "EncryptAndDecrypt.h" |
12 | @interface ViewController () |
16 | @implementation ViewController |
17 | @synthesize plainTextField; |
24 | - ( void )didReceiveMemoryWarning |
26 | [super didReceiveMemoryWarning]; |
30 | - (IBAction)backgroundTap:(id)sender{ |
31 | [plainTextField resignFirstResponder]; |
34 | - (IBAction)encrypt:(id)sender { |
36 | NSString *plainText = plainTextField.text; |
37 | NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding]; |
40 | Byte keyByte[] = {0x08,0x08,0x04,0x0b,0x02,0x0f,0x0b,0x0c,0x01,0x03,0x09,0x07,0x0c,0x03, |
41 | 0x07,0x0a,0x04,0x0f,0x06,0x0f,0x0e,0x09,0x05,0x01,0x0a,0x0a,0x01,0x09, |
44 | NSData *keyData = [[NSData alloc] initWithBytes:keyByte length:32]; |
46 | NSData *cipherTextData = [plainTextData AES256EncryptWithKey:keyData]; |
47 | Byte *plainTextByte = (Byte *)[cipherTextData bytes]; |
48 | for ( int i=0;i<[cipherTextData length];i++){ |
49 | printf ( "%x" ,plainTextByte[i]); |
运行程序,这里需要自己创建一个简单的应用程序,简单的布局:
加密后的密文:
大家可以看到这里的密文和java端的密文是一致的,这样我们就成功完成了。只要密文和密钥是一致的,那么解密应该就不会有什么问题了后面如果有需要解密的可以自己调用解密的那个方法就可以了。
如有什么不明之处欢迎大家留言,互相学习!很遗憾这里无法上传附件,代码中需要的包只能以链接的方式让各位去下了:
jce_policy-6.zip 下载链接:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
下载解压后将里边的两个jar包(local_policy.jar,US_export_policy.jar)替换掉jdk安装路径下security文件夹中的两个包。
bcprov-jdk16-139.jar 下载链接:http://www.bouncycastle.org
终于写完了。。。第一次写博文,虽然有点费时,但感觉很好!如有转载,请注明出处,谢谢大家!
NSString *str = @"AA21f0c1762a3abc299c013abe7dbcc50001DD"
怎么将里面的字符转换到Byte数组中,如下
Byte buffer[] = { 0xAA, 0x21, 0xf0, 0xc1, 0x76, 0x2a, 0x3a, ... , 0x01, 0xDD }
各位大侠恳请帮帮忙,先谢谢啦
找到答案了,
@interface NSString (NSStringHexToBytes)
-(NSData*) hexToBytes ;
@end
@implementation NSString (NSStringHexToBytes)
-(NSData*) hexToBytes {
NSMutableData* data = [NSMutableDatadata];
int idx;
for (idx = 0; idx+2 <= self.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [selfsubstringWithRange:range];
NSScanner* scanner = [NSScannerscannerWithString:hexStr];
unsignedint intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
@end
应用:
NSData *data = [str hexToBytes];
2012-11-06 18:49
提问者采纳
NSString *str = @"AA21f0c1762a3abc299c013abe7dbcc50001DD";
NSData* bytes = [str dataUsingEncoding:NSUTF8StringEncoding];
Byte * myByte = (Byte *)[bytes bytes];
NSLog(@"myByte = %s",myByte);