这两天为移动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+]; // 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 = ;
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+]; // 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 = ;
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, , toEncryptArray.Length); return Convert.ToBase64String(resultArray, , 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, , 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加密算法

    原文:iOS,Android,.NET通用AES加密算法 这两天为移动App开发API,结果实现加密验证时碰到一大坑.这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果 ...

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

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

  3. 编程之路-client学习知识点纲要(Web/iOS/Android/WP)

    Advanced:高级内容 Architect:架构设计 Core:框架底层原理分析 Language:框架经常使用语言 Objective-C Dart Swift Java Network:网络 ...

  4. PHP android ios相互兼容的AES加密算法

    APP项目用户密码传输一直没有用HTTPS,考虑到用户的隐私暂时先用AES对密码加密,以后也可以用于手机端与服务端加密交互. PHP的免费版phpAES项目,手机端解码各种不对. 好不容易找了PHP ...

  5. 【转】PHP android ios相互兼容的AES加密算法

    APP项目用户密码传输一直没有用HTTPS,考虑到用户的隐私暂时先用AES对密码加密,以后也可以用于手机端与服务端加密交互. PHP的免费版phpAES项目,手机端解码各种不对. 好不容易找了PHP ...

  6. 毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库

    毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库 在线演示地址: http://m.yunxunmi.com/ 支持 IOS Android Ipad 等不同操作系统的手持或 ...

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

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

  8. C#/IOS/Android通用加密解密方法

    原文:C#/IOS/Android通用加密解密方法 公司在做移动端ios/android,服务器提供接口使用的.net,用到加密解密这一块,也在网上找了一些方法,有些是.net加密了android解密 ...

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

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

随机推荐

  1. spring boot中注入jpa时报could not autowire.No beans of 'PersonRepository' type found

    解决方法,在repository加一个注解.如下图所示: @Component

  2. 对象序列化:pickle和shelve

    import pickle class DVD: def __init__(self,tilte,year=None,duration=None,director_id=None): self.tit ...

  3. shell常见命令

    awk awk是个很好用的东西,大量使用在linux系统分析的结果展示处理上.并且可以使用管道, input | awk ''  | output 1.首先要知道形式 awk 'command' fi ...

  4. c#中委托与事件

    参考:http://www.tracefact.net/tech/009.html 张子阳:http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/9 ...

  5. HDU 5656 CA Loves GCD (容斥)

    题意:给定一个数组,每次他会从中选出若干个(至少一个数),求出所有数的GCD然后放回去,为了使自己不会无聊,会把每种不同的选法都选一遍,想知道他得到的所有GCD的和是多少. 析:枚举gcd,然后求每个 ...

  6. java代码执行顺序

    class HelloA { public HelloA() { System.out.println("HelloA"); } { System.out.println(&quo ...

  7. Ng第三课:线性代数回顾(Linear Algebra Review)

    3.1  矩阵和向量 3.2  加法和标量乘法 3.3  矩阵向量乘法 3.4  矩阵乘法 3.5  矩阵乘法的性质 3.6  逆.转置 3.1  矩阵和向量 如图:这个是 4×2 矩阵,即 4 行  ...

  8. (转)WAMP多站点配置

    转自:http://wislab.net/archives/43.html Wamp正在被广泛使用,其傻瓜式的安装配置,使得我们可以得心应手地完成以往较为烦琐的服务器环境搭建过程,直接进入到网页程序的 ...

  9. hibernate之查询

    Query对象 方便的对数据库和持久化对象进行查询,两种表达方式:HQL和SQL; Query经常用来绑定查询参数,限制查询条数.并最终执行查询语句. HQL 查询一个简单类(查询所有) @Test ...

  10. noip第3课资料