我想关于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;
|
002 |
003 |
004 |
import java.io.UnsupportedEncodingException;
|
005 |
import java.security.Key;
|
006 |
import java.security.Security;
|
007 |
008 |
import javax.crypto.Cipher;
|
009 |
import javax.crypto.SecretKey;
|
010 |
import javax.crypto.spec.SecretKeySpec;
|
011 |
012 |
public class AES256Encryption{
|
013 |
|
014 |
/**
|
015 |
* 密钥算法
|
016 |
* java6支持56位密钥,bouncycastle支持64位
|
017 |
* */ |
018 |
public static final String KEY_ALGORITHM= "AES" ;
|
019 |
|
020 |
/**
|
021 |
* 加密/解密算法/工作模式/填充方式
|
022 |
*
|
023 |
* JAVA6 支持PKCS5PADDING填充方式
|
024 |
* Bouncy castle支持PKCS7Padding填充方式
|
025 |
* */ |
026 |
public static final String CIPHER_ALGORITHM= "AES/ECB/PKCS7Padding" ;
|
027 |
|
028 |
/**
|
029 |
*
|
030 |
* 生成密钥,java6只支持56位密钥,bouncycastle支持64位密钥
|
031 |
* @return byte[] 二进制密钥
|
032 |
* */ |
033 |
public static byte [] initkey() throws Exception{
|
034 |
|
035 |
// //实例化密钥生成器 |
036 |
// Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); |
037 |
// KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC"); |
038 |
// //初始化密钥生成器,AES要求密钥长度为128位、192位、256位 |
039 |
//// kg.init(256); |
040 |
// kg.init(128); |
041 |
// //生成密钥 |
042 |
// SecretKey secretKey=kg.generateKey(); |
043 |
// //获取二进制密钥编码形式 |
044 |
// return secretKey.getEncoded(); |
045 |
//为了便于测试,这里我把key写死了,如果大家需要自动生成,可用上面注释掉的代码
|
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 };
|
050 |
}
|
051 |
052 |
/**
|
053 |
* 转换密钥
|
054 |
* @param key 二进制密钥
|
055 |
* @return Key 密钥
|
056 |
* */ |
057 |
public static Key toKey( byte [] key) throws Exception{
|
058 |
//实例化DES密钥
|
059 |
//生成密钥
|
060 |
SecretKey secretKey= new SecretKeySpec(key,KEY_ALGORITHM);
|
061 |
return secretKey;
|
062 |
}
|
063 |
|
064 |
/**
|
065 |
* 加密数据
|
066 |
* @param data 待加密数据
|
067 |
* @param key 密钥
|
068 |
* @return byte[] 加密后的数据
|
069 |
* */ |
070 |
public static byte [] encrypt( byte [] data, byte [] key) throws Exception{
|
071 |
//还原密钥
|
072 |
Key k=toKey(key);
|
073 |
/**
|
074 |
* 实例化
|
075 |
* 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
|
076 |
* Cipher.getInstance(CIPHER_ALGORITHM,"BC")
|
077 |
*/ |
078 |
Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider());
|
079 |
Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC" );
|
080 |
//初始化,设置为加密模式
|
081 |
cipher.init(Cipher.ENCRYPT_MODE, k);
|
082 |
//执行操作
|
083 |
return cipher.doFinal(data);
|
084 |
}
|
085 |
/**
|
086 |
* 解密数据
|
087 |
* @param data 待解密数据
|
088 |
* @param key 密钥
|
089 |
* @return byte[] 解密后的数据
|
090 |
* */ |
091 |
public static byte [] decrypt( byte [] data, byte [] key) throws Exception{
|
092 |
//欢迎密钥
|
093 |
Key k =toKey(key);
|
094 |
/**
|
095 |
* 实例化
|
096 |
* 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现
|
097 |
* Cipher.getInstance(CIPHER_ALGORITHM,"BC")
|
098 |
*/ |
099 |
Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
|
100 |
//初始化,设置为解密模式
|
101 |
cipher.init(Cipher.DECRYPT_MODE, k);
|
102 |
//执行操作
|
103 |
return cipher.doFinal(data);
|
104 |
}
|
105 |
/**
|
106 |
* @param args
|
107 |
* @throws UnsupportedEncodingException
|
108 |
* @throws Exception
|
109 |
*/ |
110 |
public static void main(String[] args) throws UnsupportedEncodingException{
|
111 |
|
112 |
String str= "AES" ;
|
113 |
System.out.println( "原文:" +str);
|
114 |
115 |
//初始化密钥
|
116 |
byte [] key;
|
117 |
try {
|
118 |
key = AES256Encryption.initkey();
|
119 |
System.out.print( "密钥:" );
|
120 |
for ( int i = 0 ;i<key.length;i++){
|
121 |
System.out.printf( "%x" , key[i]);
|
122 |
}
|
123 |
System.out.print( "\n" );
|
124 |
//加密数据
|
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]);
|
129 |
}
|
130 |
System.out.print( "\n" );
|
131 |
|
132 |
//解密数据
|
133 |
data=AES256Encryption.decrypt(data, key);
|
134 |
System.out.println( "解密后:" + new String(data));
|
135 |
} catch (Exception e) {
|
136 |
// TODO Auto-generated catch block
|
137 |
e.printStackTrace();
|
138 |
}
|
139 |
|
140 |
}
|
141 |
}
|
运行程序后的结果截图:
上图可以看到密钥和密文,好了,我们来看看iOS端实现AES256加密解密的方法,有点复杂,大家耐心点看就好。
EncryptAndDecrypt.h文件
01 |
// |
02 |
// EncryptAndDecrypt.h |
03 |
// AES256EncryptionDemo |
04 |
// |
05 |
// Created by rich sun on 12-12-13. |
06 |
// Copyright (c) 2012年 rich sun. All rights reserved. |
07 |
// |
08 |
09 |
#import <Foundation/Foundation.h> |
10 |
11 |
@ class NSString;
|
12 |
13 |
@interface NSData (Encryption) |
14 |
15 |
- (NSData *)AES256EncryptWithKey:(NSData *)key; //加密
|
16 |
- (NSData *)AES256DecryptWithKey:(NSData *)key; //解密
|
17 |
- (NSString *)newStringInBase64FromData; //追加64编码
|
18 |
+ (NSString*)base64encode:(NSString*)str; //同上64编码
|
19 |
20 |
@end |
EncryptAndDecrypt.m文件
001 |
// |
002 |
// EncryptAndDecrypt.m |
003 |
// AES256EncryptionDemo |
004 |
// |
005 |
// Created by rich sun on 12-12-13. |
006 |
// Copyright (c) 2012年 rich sun. All rights reserved. |
007 |
// |
008 |
009 |
#import "EncryptAndDecrypt.h" |
010 |
#import <CommonCrypto/CommonCrypto.h> |
011 |
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
|
012 |
013 |
@implementation NSData (Encryption) |
014 |
015 |
- (NSData *)AES256EncryptWithKey:(NSData *)key //加密
|
016 |
{ |
017 |
018 |
//AES256加密,密钥应该是32位的
|
019 |
const void * keyPtr2 = [key bytes];
|
020 |
char (*keyPtr)[32] = keyPtr2;
|
021 |
022 |
//对于块加密算法,输出大小总是等于或小于输入大小加上一个块的大小
|
023 |
//所以在下边需要再加上一个块的大小
|
024 |
NSUInteger dataLength = [self length];
|
025 |
size_t bufferSize = dataLength + kCCBlockSizeAES128;
|
026 |
void *buffer = malloc (bufferSize);
|
027 |
028 |
size_t numBytesEncrypted = 0;
|
029 |
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
|
030 |
kCCOptionPKCS7Padding /*这里就是刚才说到的PKCS7Padding填充了*/ | kCCOptionECBMode,
|
031 |
[key bytes], kCCKeySizeAES256,
|
032 |
NULL, /* 初始化向量(可选) */
|
033 |
[self bytes], dataLength, /*输入*/
|
034 |
buffer, bufferSize, /* 输出 */
|
035 |
&numBytesEncrypted);
|
036 |
037 |
if (cryptStatus == kCCSuccess) {
|
038 |
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
|
039 |
}
|
040 |
free (buffer); //释放buffer
|
041 |
return nil;
|
042 |
} |
043 |
044 |
045 |
- (NSData *)AES256DecryptWithKey:(NSData *)key //解密
|
046 |
{ |
047 |
048 |
//同理,解密中,密钥也是32位的
|
049 |
const void * keyPtr2 = [key bytes];
|
050 |
char (*keyPtr)[32] = keyPtr2;
|
051 |
052 |
//对于块加密算法,输出大小总是等于或小于输入大小加上一个块的大小
|
053 |
//所以在下边需要再加上一个块的大小
|
054 |
NSUInteger dataLength = [self length];
|
055 |
size_t bufferSize = dataLength + kCCBlockSizeAES128;
|
056 |
void *buffer = malloc (bufferSize);
|
057 |
058 |
size_t numBytesDecrypted = 0;
|
059 |
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
|
060 |
kCCOptionPKCS7Padding /*这里就是刚才说到的PKCS7Padding填充了*/ | kCCOptionECBMode,
|
061 |
keyPtr, kCCKeySizeAES256,
|
062 |
NULL, /* 初始化向量(可选) */
|
063 |
[self bytes], dataLength, /* 输入 */
|
064 |
buffer, bufferSize, /* 输出 */
|
065 |
&numBytesDecrypted);
|
066 |
if (cryptStatus == kCCSuccess) {
|
067 |
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
|
068 |
}
|
069 |
free (buffer);
|
070 |
return nil;
|
071 |
} |
072 |
073 |
074 |
- (NSString *)newStringInBase64FromData //追加64编码
|
075 |
{ |
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;
|
082 |
int ix = (nib+1)*2;
|
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]];
|
087 |
}
|
088 |
}
|
089 |
return dest;
|
090 |
} |
091 |
092 |
+ (NSString*)base64encode:(NSString*)str |
093 |
{ |
094 |
if ([str length] == 0)
|
095 |
return @ "" ;
|
096 |
const char *source = [str UTF8String];
|
097 |
int strlength = strlen (source);
|
098 |
char *characters = malloc (((strlength + 2) / 3) * 4);
|
099 |
if (characters == NULL)
|
100 |
return nil;
|
101 |
NSUInteger length = 0;
|
102 |
NSUInteger i = 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++] = '=' ;
|
116 |
}
|
117 |
NSString *g = [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES];
|
118 |
return g;
|
119 |
} |
120 |
121 |
@end |
ViewController.m文件
01 |
// |
02 |
// ViewController.m |
03 |
// AES256EncryptionDemo |
04 |
// |
05 |
// Created by 孙 裔 on 12-12-13. |
06 |
// Copyright (c) 2012年 rich sun. All rights reserved. |
07 |
// |
08 |
09 |
#import "ViewController.h" |
10 |
#import "EncryptAndDecrypt.h" |
11 |
12 |
@interface ViewController () |
13 |
14 |
@end |
15 |
16 |
@implementation ViewController |
17 |
@synthesize plainTextField; |
18 |
- ( void )viewDidLoad
|
19 |
{ |
20 |
[super viewDidLoad];
|
21 |
// Do any additional setup after loading the view, typically from a nib.
|
22 |
} |
23 |
24 |
- ( void )didReceiveMemoryWarning
|
25 |
{ |
26 |
[super didReceiveMemoryWarning];
|
27 |
// Dispose of any resources that can be recreated.
|
28 |
} |
29 |
//这个函数实现了用户输入完后点击视图背景,关闭键盘 |
30 |
- (IBAction)backgroundTap:(id)sender{ |
31 |
[plainTextField resignFirstResponder];
|
32 |
} |
33 |
34 |
- (IBAction)encrypt:(id)sender { |
35 |
|
36 |
NSString *plainText = plainTextField.text; //明文
|
37 |
NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
|
38 |
|
39 |
//为了测试,这里先把密钥写死
|
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,
|
42 |
0x06,0x07,0x09,0x0d};
|
43 |
//byte转换为NSData类型,以便下边加密方法的调用
|
44 |
NSData *keyData = [[NSData alloc] initWithBytes:keyByte length:32];
|
45 |
//
|
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]);
|
50 |
}
|
51 |
52 |
} |
53 |
@end |
运行程序,这里需要自己创建一个简单的应用程序,简单的布局:
加密后的密文:
大家可以看到这里的密文和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];
NSString *str = @"AA21f0c1762a3abc299c013abe7dbcc50001DD"; NSData* bytes = [str dataUsingEncoding:NSUTF8StringEncoding]; Byte * myByte = (Byte *)[bytes bytes]; NSLog(@"myByte = %s",myByte);
相关推荐
在iOS和Android平台上实现AES加密解密是开发者经常遇到的任务,尤其对于需要跨平台传输和存储敏感信息的场景。本篇文章将详细探讨AES加密解密算法在iOS和Android平台上的实现原理以及具体步骤。 首先,AES算法基于...
AES加密有多种算法模式,下面提供两套模式的可用源码: 一、CBC(Cipher Block Chaining,加密块链)模式 二、ECB(Electronic Code Book,电子密码本)模式 其中CBC模式下,有.NET的源码。而ECB模式的,大家在网上找...
本压缩包"uniapp 前后端AES加密解密.rar"正是为了解决这一问题,它包含了在uniapp环境下实现前后端AES加密解密的方法。AES(Advanced Encryption Standard),即高级加密标准,是一种广泛使用的对称加密算法,具有...
在iOS开发中,AES(Advanced Encryption Standard)是一种广泛使用的对称加密算法,用于保护数据的安全性。AES128指的是使用128位的密钥进行加密,这提供了极高的安全级别,使得破解变得极其困难。本文将深入探讨iOS...
AES256是一种广泛使用的对称加密算法,全称为Advanced Encryption Standard with a 256-bit key size。这种加密标准在信息安全领域具有很高的安全性,被用于保护敏感数据,如密码、个人信息以及商业机密等。它基于块...
AES是一种对称加密算法,它使用相同的密钥进行加密和解密,具有速度快、安全性高的特点。本篇将详细介绍如何在iOS应用中实现AES加密解密。 一、AES加密原理 AES加密基于替换和置换操作,通过128位的块进行加密,...
**iOS中的AES128加密解密** AES(Advanced Encryption Standard),即高级加密标准,是目前广泛用于数据安全保护的一种对称加密算法。在iOS开发中,AES128是常见的加密方式,常用于保护敏感数据,如用户密码、隐私...
理解并掌握这种AES加密解密方法对于iOS开发者来说非常关键,可以有效地保护应用程序的数据安全,防止未授权访问。同时,了解如何在Objective-C中使用CommonCrypto库也可以扩展到其他加密算法的实现,如RSA或DES。在...
AES(Advanced Encryption Standard)是一种广泛应用的对称加密算法,它提供了高效且安全的数据加密。本话题将围绕“iOS AES加密 PHP解密”这一主题展开,讲解如何在iOS应用中使用AES加密数据,并在后端PHP环境中...
本资源"DES加密解密一套JAVA&IOS"提供了一套跨平台的解决方案,允许JAVA和iOS应用之间进行互操作性的加密和解密操作。 在JAVA平台上,DES加密和解密通常通过Java的`javax.crypto`包来实现。这个包提供了`Cipher`类...
AES(Advanced Encryption Standard)128位加密是一种广泛应用的对称加密算法,它为iOS、Android、Java等平台提供了强大的安全保障。本篇文章将深入探讨AES128加密解密的原理、实现方式以及在不同平台上的应用。 ...
本文将深入探讨AES加密,特别是使用CBC(Cipher Block Chaining,密码块链接)模式和PKCS5Padding填充方式,并在JavaScript、Java和iOS平台上实现这一加密过程。 **一、AES加密简介** AES是一种对称加密算法,由...
文件"js aes.txt"可能是JavaScript实现AES加密的示例代码,而"AES加密 – iOS与Java的同步实现"可能是介绍如何在iOS和Java之间实现同步加密的教程或代码示例。通过学习这些内容,开发者可以掌握如何在不同平台上实现...
本工程可以直接使用,而且与IOS,Android,JAVA 已调通。...AES加密有多种算法模式,下面提供两套模式的可用源码: 一、CBC(Cipher Block Chaining,加密块链)模式 二、ECB(Electronic Code Book,电子密码本)模式
在iOS开发中,RSA是一种广泛使用的非对称加密算法,主要应用于数据的加密和数字签名。RSA的安全性基于大整数因子分解的困难性,它包括一对密钥:公钥和私钥。公钥用于加密,私钥用于解密。在处理大量数据时,由于RSA...
总之,使用Object-C在iOS上实现RSA加密解密涉及理解算法原理、导入导出密钥、调用Security框架的API以及处理可能出现的问题。通过掌握这些知识,开发者可以创建安全的应用程序,保护用户数据的安全。