原文: iOS,Android,.NET通用AES加密算法

这两天为移动App开发API,结果实现加密验证时碰到一大坑。这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果,Android则可以,后来使用了通用的AES256加密算法才最终搞定。

搞服务器端小伙伴没有接触过iOS,所以也没料到过这种情形。他使用了AES128 with IV的加密算法,Android端可以顺利通过加密验证。

但是iOS端使用AES128算法后出现问题,虽然可以在本地加密解密,但是无法被服务器解密成功。

后来经过多方查找,才了解到一个蛋疼的事实,iOS只支持AES PKCS7Padding算法,在服务器端修改为响应算法后,顺利通过。

这里主要参考一篇博文,以下给出通用AES算法:

Objective-C:

//头文件
#import
<Foundation/Foundation.h>@interface NSData (AES)- (NSData *)AES256EncryptWithKey:(NSString *)key;- (NSData *)AES256DecryptWithKey:(NSString *)key;@end

实现代码:

#import "NSData+AES256.h"#import <CommonCrypto/CommonCryptor.h>@implementation NSData (AES)-(NSData *)AES256EncryptWithKey:(NSString *)key {    // 'key' should be 32 bytes for AES256, will be null-padded otherwise    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)        // fetch key data    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];        NSUInteger dataLength = [self length];        //See the doc: For block ciphers, the output size will always be less than or    //equal to the input size plus the size of one block.    //That's why we need to add the size of one block here    size_t bufferSize = dataLength + kCCBlockSizeAES128;    void *buffer = malloc(bufferSize);        size_t numBytesEncrypted = 0;    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,                                          keyPtr, kCCKeySizeAES256,                                          NULL /* initialization vector (optional) */,                                          [self bytes], dataLength, /* input */                                          buffer, bufferSize, /* output */                                          &numBytesEncrypted);    if (cryptStatus == kCCSuccess) {        //the returned NSData takes ownership of the buffer and will free it on deallocation        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];    }        free(buffer); //free the buffer;    return nil;}-(NSData *)AES256DecryptWithKey:(NSString *)key {    // 'key' should be 32 bytes for AES256, will be null-padded otherwise    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)        // fetch key data    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];        NSUInteger dataLength = [self length];        //See the doc: For block ciphers, the output size will always be less than or    //equal to the input size plus the size of one block.    //That's why we need to add the size of one block here    size_t bufferSize = dataLength + kCCBlockSizeAES128;    void *buffer = malloc(bufferSize);        size_t numBytesDecrypted = 0;    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,                                          keyPtr, kCCKeySizeAES256,                                          NULL /* initialization vector (optional) */,                                          [self bytes], dataLength, /* input */                                          buffer, bufferSize, /* output */                                          &numBytesDecrypted);        if (cryptStatus == kCCSuccess) {        //the returned NSData takes ownership of the buffer and will free it on deallocation        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];    }        free(buffer); //free the buffer;    return nil;}@end

C#:

#region        /// <summary>        /// 256位AES加密        /// </summary>        /// <param name="toEncrypt"></param>        /// <returns></returns>        public static string Encrypt(string toEncrypt)        {            // 256-AES key                byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);            RijndaelManaged rDel = new RijndaelManaged();            rDel.Key = keyArray;            rDel.Mode = CipherMode.ECB;            rDel.Padding = PaddingMode.PKCS7;            ICryptoTransform cTransform = rDel.CreateEncryptor();            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);            return Convert.ToBase64String(resultArray, 0, resultArray.Length);        }        /// <summary>        /// 256位AES解密        /// </summary>        /// <param name="toDecrypt"></param>        /// <returns></returns>        public static string Decrypt(string toDecrypt)        {            // 256-AES key                byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);            byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);            RijndaelManaged rDel = new RijndaelManaged();            rDel.Key = keyArray;            rDel.Mode = CipherMode.ECB;            rDel.Padding = PaddingMode.PKCS7;            ICryptoTransform cTransform = rDel.CreateDecryptor();            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);            return UTF8Encoding.UTF8.GetString(resultArray);        }        #endregion

Java

import java.io.UnsupportedEncodingException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.Arrays;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import android.util.Base64;public class AESUtils {    /**      * 加密      * @param content 需要加密的内容      * @param password  加密密码      * @return      */      private static String Key="GcA*23jKJf0df09Osf09834ljlJF0920";    public static String encode(String stringToEncode) throws NullPointerException {        try {            SecretKeySpec skeySpec = getKey(Key);            byte[] clearText = stringToEncode.getBytes("UTF8");            final byte[] iv = new byte[16];            Arrays.fill(iv, (byte) 0x00);            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);            String encrypedValue = Base64.encodeToString(cipher.doFinal(clearText), Base64.DEFAULT);            return encrypedValue;                    } catch (InvalidKeyException e) {            e.printStackTrace();        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (BadPaddingException e) {            e.printStackTrace();        } catch (NoSuchPaddingException e) {            e.printStackTrace();        } catch (IllegalBlockSizeException e) {            e.printStackTrace();        } catch (InvalidAlgorithmParameterException e) {            e.printStackTrace();        }        return "";    }                 private static SecretKeySpec getKey(String password) throws UnsupportedEncodingException {        int keyLength = 256;        byte[] keyBytes = new byte[keyLength / 8];        Arrays.fill(keyBytes, (byte) 0x0);        byte[] passwordBytes = password.getBytes("UTF-8");        int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length;        System.arraycopy(passwordBytes, 0, keyBytes, 0, length);        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");        return key;    }        }

更多相关文章

  1. [置顶] android中使用jni对字符串加解密实现分析
  2. Android逆向之旅---Android中锁屏密码算法解析以及破解方案
  3. android 图片占用进程的内存算法
  4. android MD5加密(二)
  5. Android(安卓)关于wifi管理的代码
  6. unity3d IL2CPP for android
  7. jdk和android的DES加密
  8. Android(安卓)MD5加密算法
  9. Android(安卓)MD5加密算法

随机推荐

  1. Google Analytics Advanced Configuratio
  2. android中如何取得用户手机的常用联系人(
  3. Android(安卓)Native Crash的log分析和定
  4. android 音乐播放器中播放模式的设计
  5. Android(安卓)input上报*、#键值笔记
  6. Android中LocalSocket使用
  7. Android第一个应用程序helloworld项目详
  8. Android(安卓)Studio 编译系统源码
  9. logcat使用方法
  10. android6.0以后删除HttpClient的解决方法