这两天为移动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 otherwisechar 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 heresize_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 deallocationreturn [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 otherwisechar 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 heresize_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 deallocationreturn [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="key";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;}    }

 Windows Phone&Windows Store:

 public static string Encrypt(string toEncrypt){//创建算法提供器var symmetricAlgorithm = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);//key处理IBuffer tempKey = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);CryptographicKey cryptKey = symmetricAlgorithm.CreateSymmetricKey(tempKey);// 将需要加密的数据转换为 IBuffer 类型var dateBuffer = CryptographicBuffer.ConvertStringToBinary(toEncrypt, BinaryStringEncoding.Utf8);try{// 加密数据var encrypted = CryptographicEngine.Encrypt(cryptKey,dateBuffer,null);// Debug.WriteLine(encrypted);return CryptographicBuffer.EncodeToBase64String(encrypted);}catch (Exception ex){Debug.WriteLine(ex.Message);}return null;}

iOS,Android,WP, .NET通用AES加密算法相关推荐

  1. IOS,ANDROID,.NET通用AES加密算法

    Objective-C: //头文件 #import <Foundation/Foundation.h>@interface NSData (AES) - (NSData *)AES256 ...

  2. mysql的aes加密算法查询_java mysql 通用aes加密算法

    importjavax.crypto.Cipher;importjavax.crypto.spec.SecretKeySpec;importsun.misc.BASE64Decoder;imports ...

  3. Emoji表情符号兼容方案(适用ios,android,wp等平台)

    http://blog.csdn.net/qdkfriend/article/details/7576524 Emoji表情符号兼容方案 一 什么是Emoji emoji就是表情符号:词义来自日语(え ...

  4. android 兼容ios emoji,Emoji表情符號兼容方案(適用ios,android,wp等平台)

    emoji就是表情符號:詞義來自日語(えもじ,e-moji,moji在日語中的含義是字符) 表情符號現已普遍應用於手機短信和網絡聊天軟件. emoji表情符號,在外國的手機短信里面已經是很流行使用的一 ...

  5. 适用ios,android,wp等平台手机emoji表情符号兼容方案

    一 什么是Emoji emoji就是表情符号:词义来自日语(えもじ,e-moji,moji在日语中的含义是字符) 表情符号现已普遍应用于手机短信和网络聊天软件. emoji表情符号,在外国的手机短信里 ...

  6. Android AES加密算法,现在实际上

    昨天,老板让我来看看android加密算法.于是在网上找了找,发现AES加密算法.(当然,MD5,BASE64什么http://snowolf.iteye.com/blog/379860这篇文章列举了 ...

  7. Android AES加密算法及事实上现

    昨天老大叫我看看android加密算法.于是网上找了找,找到了AES加密算法.(当然还有MD5,BASE64什么的http://snowolf.iteye.com/blog/379860这篇文章列举了 ...

  8. Android AES加密算法及其实现

    找到了AES加密算法.(当然还有MD5,BASE64什么的http://snowolf.iteye.com/blog/379860这篇文章列举了很多,但是基本都是j2se平台的,android平台不一 ...

  9. 你知道吗:Android为何比iOS和WP慢?

    你知道吗:Android为何比iOS和WP慢? [IT168评论]拥有开放互联网精神的谷歌,在短短的4年时间,将Android打造成市场份额第一的手机操作系统;拥有用户体验至上精神的乔布斯,将iOS产 ...

最新文章

  1. 如何发布Node模块到NPM社区
  2. 一道简单的面试题:竟然有90%的程序员不能把这个算法完全写正确。。。
  3. Jmeter录制app脚本
  4. 获得国内中国电信,网通,铁通的最新ip段的方法
  5. Linux虚拟文件系统
  6. jsf集成spring_Spring JSF集成
  7. apache kafkac系列lient发展-java
  8. Ubuntu -- 无法正常安装卸载ssh以及chattr无反应的问题
  9. python上传文件到oss_python实现上传文件到OSS
  10. 在URL中实现简易的WebAPI验签
  11. 阿里云国际站:云端实时渲染 阿里云用算力让三星堆“活过来”
  12. 计算机专业本科毕业论文字数要求,计算机科学与技术专业本科毕业设计论文要求...
  13. [leetcode]1438. 绝对差不超过限制的最长连续子数组
  14. 机器学习入门的绝佳材料:斯坦福大学机器学习课程原始讲义(含公开课视频)
  15. python兔子_python学习:关于生兔子问题
  16. oracle 查询指定时间范围
  17. 重新排列数组[数组] 给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,...,xn,y1,y2,...,yn] 的格式排列。请你将数组按 [x1,y1,x2,y2,...,x
  18. 在线扫描php后门_webshell后门扫描-PHP版
  19. python 素数库_使用Python判断质数(素数)的简单方法讲解
  20. 循环神经网络(RNN)预测股票价格,附带例子和完整代码

热门文章

  1. php mvc实例下载,php实现简单的MVC框架实例
  2. 7.1 pdo 宝塔面板php_记宝塔面板中 PHP升级到 7.3.16安全版本概要
  3. iphone清理缓存小技巧_苹果手机清理垃圾小技巧!小内存也不发愁
  4. python中内置的四种数值类型为_浅谈python语言四种数值类型
  5. Java项目:校园二手市场系统(java+SSM+mysql+maven+tomcat)
  6. linux脚本自定义赋值,JMeter——运用BeanShell给自定义的变量动态赋值
  7. java modbus协议
  8. vue写一个通用的toast弹窗 toast 弹窗 提示
  9. Spring Boot 整合Pagehelper(为什么PageHelper分页不生效)
  10. Javascript - prototype、__proto__、constructor