aes ios java
2016-12-12 09:58:00 weixin_34237596 阅读数 8

AES是开发中常用的加密算法之一。然而由于前后端开发环境差异,导致出现前端加密而后端不能解密的情况出现。然而无论什么环境,AES的算法总是相同的, 因此导致结果不一致的原因在于加密配置的参数不一致 。于是先来看看在两个平台使用AES加密时需要统一的几个参数。

  • 密钥长度(Key Size)

  • 加密模式(Cipher Mode)

  • 填充方式(Padding)

  • 初始向量(Initialization Vector)
    1.密钥长度

AES算法下,key的长度有三种:128、192和256 bits。由于历史原因,JDK默认只支持不大于128 bits的密钥,而128 bits的key已能够满足商用安全需求。因此本例先使用AES-128。(Java使用大于128 bits的key方法在文末提及)

2.加密模式

AES属于分组加密(Block Cipher),块加密中有CBC、ECB、CTR、OFB、CFB等几种工作模式。本例统一使用CBC模式。

3.填充方式

由于分组加密只能对特定长度的数据块进行加密,因此CBC、ECB模式需要在最后一数据块加密前进行数据填充。(CFB,OFB和CTR模式由于与key进行加密操作的是上一块加密后的密文,因此不需要对最后一段明文进行填充)

在iOS SDK中提供了PKCS7Padding,而JDK则提供了PKCS5Padding。原则上PKCS5Padding限制了填充的Block Size为8 bytes,而Java实际上当块大于该值时,其PKCS5Padding与PKCS7Padding是相等的:每需要填充χ个字节,填充的值就是χ。
4.初始向量

使用除ECB以外的其他加密模式均需要传入一个初始向量,其大小与Block Size相等(AES的Block Size为128 bits),而两个平台的API文档均指明当不传入初始向量时,系统将默认使用一个全0的初始向量。

有了上述的基础之后,可以开始分别在两个平台进行实现了。

iOS实现

先定义一个初始向量的值。

NSString *const kInitVector = @"16-Bytes--String";// 16个字节的初始化向量

确定密钥长度,这里选择 AES-128。

size_t const kKeySize = kCCKeySizeAES128;

加密方法

+ (NSString *)encryptAES:(NSString *)content key:(NSString *)key {
NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = contentData.length;
// 为结束符'\\0' +1
char keyPtr[kKeySize + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
// 密文长度 <= 明文长度 + BlockSize
size_t encryptSize = dataLength + kCCBlockSizeAES128;
void *encryptedBytes = malloc(encryptSize);
size_t actualOutSize = 0;
NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,  // 系统默认使用 CBC,然后指明使用 PKCS7Padding
keyPtr,
kKeySize,
initVector.bytes,
contentData.bytes,
dataLength,
encryptedBytes,
encryptSize,
&actualOutSize);
if (cryptStatus == kCCSuccess) {
// 对加密后的数据进行 base64 编码
return [[NSData dataWithBytesNoCopy:encryptedBytes length:actualOutSize] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}
free(encryptedBytes);
return nil;
}

解密方法

+ (NSString *)decryptAES:(NSString *)content key:(NSString *)key {
// 把 base64 String 转换成 Data
NSData *contentData = [[NSData alloc] initWithBase64EncodedString:content options:NSDataBase64DecodingIgnoreUnknownCharacters];
NSUInteger dataLength = contentData.length;
char keyPtr[kKeySize + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
size_t decryptSize = dataLength + kCCBlockSizeAES128;
void *decryptedBytes = malloc(decryptSize);
size_t actualOutSize = 0;
NSData *initVector = [kInitVector dataUsingEncoding:NSUTF8StringEncoding];
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
keyPtr,
kKeySize,
initVector.bytes,
contentData.bytes,
dataLength,
decryptedBytes,
decryptSize,
&actualOutSize);
if (cryptStatus == kCCSuccess) {
return [[NSString alloc] initWithData:[NSData dataWithBytesNoCopy:decryptedBytes length:actualOutSize] encoding:NSUTF8StringEncoding];
}
free(decryptedBytes);
return nil;
}

Java实现

同理先在类中定义一个初始向量,需要与iOS端的统一。

private static final String IV_STRING = "16-Bytes--String";

另 Java 不需手动设置密钥大小,系统会自动根据传入的 Key 进行判断。

加密方法

public static String encryptAES(String content, String key)
throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, UnsupportedEncodingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] byteContent = content.getBytes("UTF-8");
// 注意,为了能与 iOS 统一
// 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
// 指定加密的算法、工作模式和填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryptedBytes = cipher.doFinal(byteContent);
// 同样对加密后数据进行 base64 编码
Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(encryptedBytes);
}

解密方法

public static String decryptAES(String content, String key)
throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
// base64 解码
Decoder decoder = Base64.getDecoder();
byte[] encryptedBytes = decoder.decode(content);
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] result = cipher.doFinal(encryptedBytes);
return new String(result, "UTF-8");
}

至此,AES 在 iOS 与 Java 同步实现完成。

注意以上实现的是 AES-128,因此方法传入的 key 需为长度为 16 的字符串。

关于Java使用大于128 bits的key

到Oracle官网下载对应Java版本的 JCE ,解压后放到 JAVA_HOME/jre/lib/security/ ,然后修改 iOS 端的 kKeySize 和两端对应的 key 即可。

github链接:https://github.com/WelkinXie/AESCipher-iOS

2015-09-16 16:43:41 blueair521 阅读数 1181

1、环境:JDK6 


2、涉及JAR包:

bcprov-jdk15on-152.jar 下载地址:http://www.bouncycastle.org/latest_releases.html 存在位置项目lib目录下

local_policy.jar、US_export_policy.jar 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html 当前使用JDK路径下:\jre\lib\security替换源文件

1、JAVA和ANDROID端:


package encrypt.ios;

 
 
import java.io.UnsupportedEncodingException;
import java.security.Key;  
import java.security.Security;
 



import javax.crypto.Cipher;  
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;  
import javax.crypto.spec.SecretKeySpec;  

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
public class AES256Encryption{  
     
         /** 
         * 密钥算法 
         * java6支持56位密钥,bouncycastle支持64位 
         * */ 
        public static final String KEY_ALGORITHM="AES";  
           
        /** 
         * 加密/解密算法/工作模式/填充方式 
         *  
         * JAVA6 支持PKCS5PADDING填充方式 
         * Bouncy castle支持PKCS7Padding填充方式 
         * */ 
        public static final String CIPHER_ALGORITHM="AES/ECB/PKCS7Padding";  
           
        /** 
         *  
         * 生成密钥,java6只支持56位密钥,bouncycastle支持64位密钥 
         * @return byte[] 二进制密钥 
         * */ 
        public static byte[] initkey() throws Exception{  
               
        	
          //实例化密钥生成器  
          Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
          KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM, "BC");  
          //初始化密钥生成器,AES要求密钥长度为128位、192位、256位  
            kg.init(256);  
//          kg.init(128); 
//          //生成密钥  
          SecretKey secretKey=kg.generateKey();  
          //获取二进制密钥编码形式  
          return secretKey.getEncoded();  
           /* //为了便于测试,这里我把key写死了,如果大家需要自动生成,可用上面注释掉的代码
            return new byte[] { 0x08, 0x08, 0x04, 0x0b, 0x02, 0x0f, 0x0b, 0x0c,
                    0x01, 0x03, 0x09, 0x07, 0x0c, 0x03, 0x07, 0x0a, 0x04, 0x0f,
                    0x06, 0x0f, 0x0e, 0x09, 0x05, 0x01, 0x0a, 0x0a, 0x01, 0x09,
                    0x06, 0x07, 0x09, 0x0d };*/
        }
 
        /** 
         * 转换密钥 
         * @param key 二进制密钥 
         * @return Key 密钥 
         * */ 
        public static Key toKey(byte[] key) throws Exception{  
            //实例化DES密钥  
            //生成密钥  
            SecretKey secretKey=new SecretKeySpec(key,KEY_ALGORITHM);  
            return secretKey;  
        }  
           
        /** 
         * 加密数据 
         * @param data 待加密数据 
         * @param key 密钥 
         * @return byte[] 加密后的数据 
         * */ 
        public static byte[] encrypt(byte[] data,byte[] key) throws Exception{  
            //还原密钥  
            Key k=toKey(key);  
            /** 
             * 实例化 
             * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 
             * Cipher.getInstance(CIPHER_ALGORITHM,"BC") 
             */ 
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");  
            //初始化,设置为加密模式  
            cipher.init(Cipher.ENCRYPT_MODE, k);  
            //执行操作  
            return cipher.doFinal(data);  
        }  
        
        /** 
         * 加密数据 
         * @param data 待加密数据 
         * @param key 密钥 
         * @return byte[] 加密后的数据 
         * */ 
        public static byte[] encrypt(byte[] data,String key) throws Exception{  
            //还原密钥  
            Key k=toKey((new BASE64Decoder()).decodeBuffer(key));  
            /** 
             * 实例化 
             * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 
             * Cipher.getInstance(CIPHER_ALGORITHM,"BC") 
             */ 
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");  
            //初始化,设置为加密模式  
            cipher.init(Cipher.ENCRYPT_MODE, k);  
            //执行操作  
            return cipher.doFinal(data);  
        }  
        /** 
         * 解密数据 
         * @param data 待解密数据 
         * @param key 密钥 
         * @return byte[] 解密后的数据 
         * */ 
        public static byte[] decrypt(byte[] data,byte[] key) throws Exception{  
            //欢迎密钥  
            Key k =toKey(key);  
            /** 
             * 实例化 
             * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 
             * Cipher.getInstance(CIPHER_ALGORITHM,"BC") 
             */ 
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");  
            //初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, k);  
            //执行操作  
            return cipher.doFinal(data);  
        }  
        
        /** 
         * 解密数据 
         * @param data 待解密数据 
         * @param key 密钥 
         * @return byte[] 解密后的数据 
         * */ 
        public static byte[] decrypt(byte[] data,String key) throws Exception{  
            //欢迎密钥  
            Key k =toKey((new BASE64Decoder()).decodeBuffer(key));  
            /** 
             * 实例化 
             * 使用 PKCS7PADDING 填充方式,按如下方式实现,就是调用bouncycastle组件实现 
             * Cipher.getInstance(CIPHER_ALGORITHM,"BC") 
             */ 
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM, "BC");  
            //初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, k);  
            //执行操作  
            return cipher.doFinal(data);  
        }  
        /** 
         * @param args 
         * @throws UnsupportedEncodingException 
         * @throws Exception  
         */ 
        public static void main(String[] args) throws UnsupportedEncodingException{  
             
            String str="AES";  
            System.out.println("原文:"+str);  
 
            //初始化密钥  
            byte[] key;
            try {
                key = (new BASE64Decoder()).decodeBuffer("Fum0rCudZw/fvNCXi05o/NGUqNQuZizD/+xK1FarK38=");//AES256Encryption.initkey();
                System.out.println("BASE64密钥:" + (new BASE64Encoder()).encodeBuffer(key));
                System.out.print("\n");
                System.out.println("密钥长度:"+key.length);  
                System.out.print("\n");
                System.out.println("密钥BYTE:"+key.toString());  
                System.out.print("\n");
                System.out.print("密钥:");  
                for(int i = 0;i<key.length;i++){
                    System.out.printf("%x", key[i]);
                }
                System.out.print("\n");
                //加密数据  
                byte[] data=AES256Encryption.encrypt(str.getBytes(), key);  
                System.out.print("加密后:"); 
                for(int i = 0;i<data.length;i++){
                    System.out.printf("%x", data[i]);
                }
                System.out.print("\n");
                String dateBase64 = new BASE64Encoder().encodeBuffer(data );
                 System.out.println("加密后BSE64:" + new BASE64Encoder().encodeBuffer(data));
                //解密数据  
                data=AES256Encryption.decrypt(new BASE64Decoder().decodeBuffer("V05aWtYB3G+a689gCGe4CWeFgKu1/X2Zmk9XUD6QflxdbQtjExxZe2PAdFqYnB+c/wCj40VW6ycSmG/rTLdkjA=="), key);  
                System.out.println("解密后:"+new String(data)); 
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  
              
        }  
    }

2、IOS端

EncryptAndDecrypt.h文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//
//  EncryptAndDecrypt.h
//  AES256EncryptionDemo
//
//  Created by rich sun on 12-12-13.
//  Copyright (c) 2012年 rich sun. All rights reserved.
//
 
#import <Foundation/Foundation.h>
 
@class NSString;
 
@interface NSData (Encryption)
 
- (NSData *)AES256EncryptWithKey:(NSData *)key;   //加密
- (NSData *)AES256DecryptWithKey:(NSData *)key;   //解密
- (NSString *)newStringInBase64FromData;            //追加64编码
+ (NSString*)base64encode:(NSString*)str;           //同上64编码
 
@end
EncryptAndDecrypt.m文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//
//  EncryptAndDecrypt.m
//  AES256EncryptionDemo
//
//  Created by rich sun on 12-12-13.
//  Copyright (c) 2012年 rich sun. All rights reserved.
//
 
#import "EncryptAndDecrypt.h"
#import <CommonCrypto/CommonCrypto.h>
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
@implementation NSData (Encryption)
 
- (NSData *)AES256EncryptWithKey:(NSData *)key   //加密
{
 
    //AES256加密,密钥应该是32位的
    const void * keyPtr2 = [key bytes];
    char (*keyPtr)[32] = keyPtr2;
 
    //对于块加密算法,输出大小总是等于或小于输入大小加上一个块的大小
    //所以在下边需要再加上一个块的大小
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
 
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding/*这里就是刚才说到的PKCS7Padding填充了*/ | kCCOptionECBMode,
                                          [key bytes], kCCKeySizeAES256,
                                          NULL,/* 初始化向量(可选) */
                                          [self bytes], dataLength,/*输入*/
                                          buffer, bufferSize,/* 输出 */
                                          &numBytesEncrypted);
 
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);//释放buffer
    return nil;
}
 
 
- (NSData *)AES256DecryptWithKey:(NSData *)key   //解密
{
 
    //同理,解密中,密钥也是32位的
    const void * keyPtr2 = [key bytes];
    char (*keyPtr)[32] = keyPtr2;
 
    //对于块加密算法,输出大小总是等于或小于输入大小加上一个块的大小
    //所以在下边需要再加上一个块的大小
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
 
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding/*这里就是刚才说到的PKCS7Padding填充了*/ | kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL,/* 初始化向量(可选) */
                                          [self bytes], dataLength,/* 输入 */
                                          buffer, bufferSize,/* 输出 */
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }
    free(buffer);
    return nil;
}
 
 
- (NSString *)newStringInBase64FromData            //追加64编码
{
    NSMutableString *dest = [[NSMutableString alloc] initWithString:@""];
    unsigned char * working = (unsigned char *)[self bytes];
    int srcLen = [self length];
    for (int i=0; i<srcLen; i += 3) {
        for (int nib=0; nib<4; nib++) {
            int byt = (nib == 0)?0:nib-1;
            int ix = (nib+1)*2;
            if (i+byt >= srcLen) break;
            unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F);
            if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F);
            [dest appendFormat:@"%c", base64[curr]];
        }
    }
    return dest;
}
 
+ (NSString*)base64encode:(NSString*)str
{
    if ([str length] == 0)
        return @"";
    const char *source = [str UTF8String];
    int strlength  = strlen(source);
    char *characters = malloc(((strlength + 2) / 3) * 4);
    if (characters == NULL)
        return nil;
    NSUInteger length = 0;
    NSUInteger i = 0;
    while (i < strlength) {
        char buffer[3] = {0,0,0};
        short bufferLength = 0;
        while (bufferLength < 3 && i < strlength)
            buffer[bufferLength++] = source[i++];
        characters[length++] = base64[(buffer[0] & 0xFC) >> 2];
        characters[length++] = base64[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
        if (bufferLength > 1)
            characters[length++] = base64[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
        else characters[length++] = '=';
        if (bufferLength > 2)
            characters[length++] = base64[buffer[2] & 0x3F];
        else characters[length++] = '=';
    }
    NSString *g = [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES];
    return g;
}
 
@end
      ViewController.m文件


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//
//  ViewController.m
//  AES256EncryptionDemo
//
//  Created by 孙 裔 on 12-12-13.
//  Copyright (c) 2012年 rich sun. All rights reserved.
//
 
#import "ViewController.h"
#import "EncryptAndDecrypt.h"
 
@interface ViewController ()
 
@end
 
@implementation ViewController
@synthesize plainTextField;
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
 
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
//这个函数实现了用户输入完后点击视图背景,关闭键盘
- (IBAction)backgroundTap:(id)sender{
    [plainTextField resignFirstResponder];
}
 
- (IBAction)encrypt:(id)sender {
     
    NSString *plainText = plainTextField.text;//明文
    NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
     
    //为了测试,这里先把密钥写死
    Byte keyByte[] = {0x08,0x08,0x04,0x0b,0x02,0x0f,0x0b,0x0c,0x01,0x03,0x09,0x07,0x0c,0x03,
        0x07,0x0a,0x04,0x0f,0x06,0x0f,0x0e,0x09,0x05,0x01,0x0a,0x0a,0x01,0x09,
        0x06,0x07,0x09,0x0d};
    //byte转换为NSData类型,以便下边加密方法的调用
    NSData *keyData = [[NSData alloc] initWithBytes:keyByte length:32];
    //
    NSData *cipherTextData = [plainTextData AES256EncryptWithKey:keyData];
    Byte *plainTextByte = (Byte *)[cipherTextData bytes];
    for(int i=0;i<[cipherTextData length];i++){
        printf("%x",plainTextByte[i]);
    }
 
}
@end

本文原文转至:http://my.oschina.net/nicsun/blog/95632?p=2#comments

2016-04-19 16:31:38 a1031359915 阅读数 6200

下载地址:http://download.csdn.net/detail/a1031359915/9495948

在网上找了很多相关的AES加密方式,遇到的问题有:1、ios与Android调通,而java后台不能使用;2、Android与java调通,ios不能使用


在搜索大片资源后,终于发现了一款适合的,我们都是代码搬运工,(*^__^*) 嘻嘻……


import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化;
 */
public class AESOperator {

    /*
     * 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
     */
    private String sKey = "7856412346543216";
    private String ivParameter = "0392039203920300";
    private static AESOperator instance = null;

    private AESOperator() {

    }

    public static AESOperator getInstance() {
        if (instance == null)
            instance = new AESOperator();
        return instance;
    }

    public static String Encrypt(String encData ,String secretKey,String vector) throws Exception {

        if(secretKey == null) {
            return null;
        }
        if(secretKey.length() != 16) {
            return null;
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = secretKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8"));
        return Base64.encode(encrypted);// 此处使用BASE64做转码。
    }


    // 加密
    public 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 Base64.encode(encrypted);// 此处使用BASE64做转码。
    }

    // 解密
    public String decrypt(String sSrc) throws Exception {
        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 = Base64.decode(sSrc);// 先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original, "utf-8");
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }

    public String decrypt(String sSrc,String key,String ivs) throws Exception {
        try {
            byte[] raw = key.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivs.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = Base64.decode(sSrc);// 先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original, "utf-8");
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }

    public static String encodeBytes(byte[] bytes) {
        StringBuffer strBuf = new StringBuffer();

        for (int i = 0; i < bytes.length; i++) {
            strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
            strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
        }

        return strBuf.toString();
    }

    public static void test() {
        try {

            // 需要加密的字串
            String cSrc = "love";

            // 加密
            long lStart = System.currentTimeMillis();
            String enString = AESOperator.getInstance().encrypt(cSrc);
            System.out.println("1:" + enString);

            long lUseTime = System.currentTimeMillis() - lStart;
            System.out.println("2:" + lUseTime + "ms");
            // 解密
            lStart = System.currentTimeMillis();
            String DeString = AESOperator.getInstance().decrypt(enString);
            System.out.println("3:" + DeString);
            lUseTime = System.currentTimeMillis() - lStart;
            System.out.println("4:" + lUseTime + "ms");
        } catch (Exception e) {
            e.getMessage();
        }
    }


}


2016-11-14 11:51:19 qq_33237207 阅读数 929

先上代码:点击下载

代码内容如上,可以自行下载调试,亲测有用哦~


值得说明的是:

android代码可以稍作修改,然后直接用在java AES加密代码上(因为两者语言相通嘛~),但是试了一下,会报错:"java.security.InvalidKeyException: Illegal key size"异常。

为什么呢?因为jdk,所以解决办法请看下面的链接:

点击打开链接


另外一点值得说明的是:

虽然代码相同,但是结果却略有差异:

android代码是可以对汉字进行加密和解密的;

java代码虽然可以对汉字加密,但是解密时汉字就会乱码。(有办法的同学,欢迎底下评论,方便你我他~大笑)。



2015-08-28 23:22:00 weixin_34062469 阅读数 8

移动端越来越火了,我们在开发过程中,总会碰到要和移动端打交道的场景,比如.NET和android或者iOS的打交道。为了让数据交互更安全,我们需要对数据进行加密传输。今天研究了一下,把几种语言的加密都实践了一遍,实现了.NET,java(android),iOS都同一套的加密算法,下面就分享给大家。

AES加密有多种算法模式,下面提供两套模式的可用源码。

加密方式:

  1. 先将文本AES加密
  2. 返回Base64转码

解密方式:

  1. 将数据进行Base64解码
  2. 进行AES解密

一、CBC(Cipher Block Chaining,加密块链)模式

是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度.

  • 密钥
  • 密钥偏移量

java/adroid加密AESOperator类:

package com.bci.wx.base.util;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


/**
 * AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化;
 */
public class AESOperator {

    /*
     * 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
     */
    private String sKey = "smkldospdosldaaa";//key,可自行修改
    private String ivParameter = "0392039203920300";//偏移量,可自行修改
    private static AESOperator instance = null;

    private AESOperator() {

    }

    public static AESOperator getInstance() {
        if (instance == null)
            instance = new AESOperator();
        return instance;
    }
    
public static String Encrypt(String encData ,String secretKey,String vector) throws Exception {
        
        if(secretKey == null) {
            return null;
        }
        if(secretKey.length() != 16) {
            return null;
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = secretKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8"));
        return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
    }


    // 加密
    public 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 String decrypt(String sSrc) throws Exception {
        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 String decrypt(String sSrc,String key,String ivs) throws Exception {
        try {
            byte[] raw = key.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivs.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 String encodeBytes(byte[] bytes) {
        StringBuffer strBuf = new StringBuffer();

        for (int i = 0; i < bytes.length; i++) {
            strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
            strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
        }

        return strBuf.toString();
    }

    public static void main(String[] args) throws Exception {
        // 需要加密的字串
        String cSrc = "[{\"request_no\":\"1001\",\"service_code\":\"FS0001\",\"contract_id\":\"100002\",\"order_id\":\"0\",\"phone_id\":\"13913996922\",\"plat_offer_id\":\"100094\",\"channel_id\":\"1\",\"activity_id\":\"100045\"}]";
        
        // 加密
        long lStart = System.currentTimeMillis();
        String enString = AESOperator.getInstance().encrypt(cSrc);
        System.out.println("加密后的字串是:" + enString);

        long lUseTime = System.currentTimeMillis() - lStart;
        System.out.println("加密耗时:" + lUseTime + "毫秒");
        // 解密
        lStart = System.currentTimeMillis();
        String DeString = AESOperator.getInstance().decrypt(enString);
        System.out.println("解密后的字串是:" + DeString);
        lUseTime = System.currentTimeMillis() - lStart;
        System.out.println("解密耗时:" + lUseTime + "毫秒");
    }

}

 

.NET AES加密解密:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace AES_Dome
{
    class Program
    {
        private static string key = "smkldospdosldaaa";//key,可自行修改
        private static string iv = "0392039203920300"; //偏移量,可自行修改
        static void Main(string[] args)
        {
            string encrytpData = Encrypt("abc", key, iv);
            Console.WriteLine(encrytpData);

            string decryptData = Decrypt("5z9WEequVr7qtd+WoxV+Kw==", key, iv);
            Console.WriteLine(decryptData);

            Console.ReadLine();
        }
        public static string Encrypt(string toEncrypt, string key, string iv)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            RijndaelManaged rDel = new RijndaelManaged();
            rDel.BlockSize = 128;
            rDel.KeySize = 256;
            rDel.FeedbackSize = 128;
            rDel.Padding = PaddingMode.PKCS7;
            rDel.Key = keyArray;
            rDel.IV = ivArray;
            rDel.Mode = CipherMode.CBC;

            ICryptoTransform cTransform = rDel.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        public static string Decrypt(string toDecrypt, string key, string iv)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
            byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);

// 这里的模式,请保持和上面加密的一样。但源代码里,这个地方并没有修正,虽然也能正确解密。看到博客的朋友,请自行修改。
// 这是个人疏忽的地址,感谢@jojoka 的提醒。 RijndaelManaged rDel
= new RijndaelManaged(); //rDel.Key = keyArray; //rDel.IV = ivArray; //rDel.Mode = CipherMode.CBC; //rDel.Padding = PaddingMode.Zeros;
        rDel.BlockSize = 128;
            rDel.KeySize = 256;
            rDel.FeedbackSize = 128;
            rDel.Padding = PaddingMode.PKCS7;
            rDel.Key = keyArray;
            rDel.IV = ivArray;
            rDel.Mode = CipherMode.CBC;
    ICryptoTransform cTransform = rDel.CreateDecryptor(); 

    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

    return UTF8Encoding.UTF8.GetString(resultArray);
  }
}
}

 

iOS源码,请下载源码,源码里有包含。

java,.net,iOS,android通用AES加密解密源码:点击下载

二、ECB(Electronic Code Book,电子密码本)模式

是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。

只需要提供密码即可。

iOS,android,java已调通源码:源码下载

AES在线加解密验证工具: http://www.seacha.com/tools/aes.html

 

 

没有更多推荐了,返回首页