这两天为移动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. Codeforces Round #538 (Div. 2) C 数论 + 求b进制后缀零

    https://codeforces.com/contest/1114/problem/C 题意 给你一个数n(<=1e8),要你求出n!在b进制下的后缀零个数(b<=1e12) 题解 a ...

  2. TCP/IP协议(3):数据链路层

    OSI数据链路层上的协议有Ethernet/IEEE802.3/IEEE802.4/IEEE802.5. ARP.RARP等. 1.Ethernet(以太网) 链路层支持很多协议,比如Ethernet ...

  3. Oracle中根据当前时间和活动类型去数据库查询活动id

    活动类型默认是1,代表邀请好友 select * from t_invite_activityinfo twhere sysdate >= t.begintime and sysdate< ...

  4. IntelliJ IDEA 2017版 spring-boot2.0.4+mybatis+Redis处理高并发,穿透问题

    一.当采用reddis缓存的时候,如果同时,一万次访问,那么就会有10000次访问数据库所以就会对数据库造成巨大压力,这时候,就要用到线程 1.方法体上加锁(优点,防护住了并发锁,缺点降低了内存效率) ...

  5. winSockets编程(四)阻塞模式(服务端)

    在阻塞模式下,在I/O操作完成前,执行的操作函数将一直等候而不会立即返回,该函数所在的线程会阻塞在这里.相反,在非阻塞模式下,套接字函数立即返回,而不管I/O是否完成. 重点知识和思想: ////// ...

  6. js基础学习笔记(三)

    3.1 认识DOM 文档对象模型DOM(Document Object Model)定义访问和处理HTML文档的标准方法.DOM 将HTML文档呈现为带有元素.属性和文本的树结构(节点树). 先来看看 ...

  7. 解决mac安装homebrew后报错-bash: brew: command not found

    解决mac安装homebrew后报错-bash: brew: command not found     参照官网上很简单的一句安装命令, /usr/bin/ruby -e "$(curl ...

  8. BUG 图片元素img下 高度超出 出现多余空白

    BUG 图片元素img下 高度超出 出现多余空白 1.将图片转换为块级对象 即,设置img为“display:block;”.   2.设置图片的垂直对齐方式 即设置图片的vertical-align ...

  9. output.php

    <?php /** * */ class Output { function __construct() { $this->_zlib_oc = @ini_get('zlib.output ...

  10. 《如何阅读it技术书》课堂笔记——51cto

    对一些书的看法: “21天精通JAVA之类”的书,好好理解精通二字,哪里有这么快就能学的会. 吐槽新人: Oop理论,别写出来的都是面向过程式. 桌面乱七八糟. 对新人分享一些经验: 阅读时自我提神的 ...