基于OpenSSL的RSA加密应用(非算法)
基于OpenSSL的RSA加密应用(非算法)
iOS开发中的小伙伴应该是经常用der和p12进行加密解密,而且在通常加密不止一种加密算法,还可以加点儿盐吧本文章主要阐述的是在iOS中基于openSLL的RSA加密。一共有两种方式,一种是基于p12加密解密的,还有一种是博客园官方提供的公钥字符串加密的,其实两种都差不多,只不过在iOS中支持crt格式的加密,其实也是一样的吧下面就来看看两种加密的应用。。。
一、RSA加密工具类(der和p12)~
二、OpenSSL 生成密钥示例~
三、der和p12加密解密Demo
四、公钥字符串加密工具类~
五、公钥加密Demo
六、一个关于RSA加密困扰了我几天的问题~
说在前面的话本文RSA加密算法并非笔者本人所作RSA算法网上有一大堆的demo,不过笔者观察核心的代码也就只有一两个版本所以,笔者也小小的借鉴了一下
一、RSA加密工具类(der和p12)~
本加密工具适用于DES,AES,RSA加密下面是代码,不做讲解因为核心算法的代码不是本人写的笔者只做了整理和封装
CryptorTools.h
//
//  CryptorTools.h
//  加密/解密工具
//
//  Created by Erma on 15/4/26.
//  Copyright (c) 2015年 Erma. All rights reserved.
//
#import <Foundation/Foundation.h>
///  加密工具类
///  提供RSA & AES & DES加密方法
@interface CryptorTools : NSObject
#pragma mark - DES 加密/解密
///  DES 加密
///
///  @param data      要加密的二进制数据
///  @param keyString 加密密钥
///  @param iv        IV向量
///
///  @return 加密后的二进制数据
+ (NSData *)DESEncryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv;
///  DES 加密字符串
///
///  @param string    要加密的字符串
///  @param keyString 加密密钥
///  @param iv        IV向量
///
///  @return 加密后的 BASE64 编码字符串
+ (NSString *)DESEncryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
///  DES 解密
///
///  @param data      要解密的二进制数据
///  @param keyString 解密密钥
///  @param iv        IV向量
///
///  @return 解密后的二进制数据
+ (NSData *)DESDecryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv;
///  DES 解密
///
///  @param string    要解密的 BASE64 编码字符串
///  @param keyString 解密密钥
///  @param iv        IV向量
///
///  @return 解密后的二进制数据
+ (NSString *)DESDecryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
#pragma mark - AES 加密/解密
///  AES 加密
///
///  @param data      要加密的二进制数据
///  @param keyString 加密密钥
///  @param iv        IV向量
///
///  @return 加密后的二进制数据
+ (NSData *)AESEncryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv;
///  AES 加密字符串
///
///  @param string    要加密的字符串
///  @param keyString 加密密钥
///  @param iv        IV向量
///
///  @return 加密后的 BASE64 编码字符串
+ (NSString *)AESEncryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
///  AES 解密
///
///  @param data      要解密的二进制数据
///  @param keyString 解密密钥
///  @param iv        IV向量
///
///  @return 解密后的二进制数据
+ (NSData *)AESDecryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv;
///  AES 解密
///
///  @param string    要解密的 BASE64 编码字符串
///  @param keyString 解密密钥
///  @param iv        IV向量
///
///  @return 解密后的二进制数据
+ (NSString *)AESDecryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
#pragma mark - RSA 加密/解密算法
///  加载公钥
///
///  @param filePath DER 公钥文件路径
- (void)loadPublicKeyWithFilePath:(NSString *)filePath;
///  加载私钥
///
///  @param filePath P12 私钥文件路径
///  @param password P12 密码
- (void)loadPrivateKey:(NSString *)filePath password:(NSString *)password;
///  RSA 加密数据
///
///  @param data 要加密的数据
///
///  @return 加密后的二进制数据
- (NSData *)RSAEncryptData:(NSData *)data;
///  RSA 加密字符串
///
///  @param string 要加密的字符串
///
///  @return 加密后的 BASE64 编码字符串
- (NSString *)RSAEncryptString:(NSString *)string;
///  RSA 解密数据
///
///  @param data 要解密的数据
///
///  @return 解密后的二进制数据
- (NSData *)RSADecryptData:(NSData *)data;
///  RSA 解密字符串
///
///  @param string 要解密的 BASE64 编码字符串
///
///  @return 解密后的字符串
- (NSString *)RSADecryptString:(NSString *)string;
@end
CryptorTools.m
//
//  CryptorTools.m
//  加密/解密工具
//
//  Created by Erma on 15/4/26.
//  Copyright (c) 2015年 Erma. All rights reserved.
//
#import "CryptorTools.h"
#import <CommonCrypto/CommonCrypto.h>
// 填充模式
#define kTypeOfWrapPadding		kSecPaddingPKCS1
@interface CryptorTools() {
SecKeyRef _publicKeyRef;                             // 公钥引用
SecKeyRef _privateKeyRef;                            // 私钥引用
}
@end
@implementation CryptorTools
#pragma mark - DES 加密/解密
#pragma mark 加密
+ (NSData *)DESEncryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv {
return [self CCCryptData:data algorithm:kCCAlgorithmDES operation:kCCEncrypt keyString:keyString iv:iv];
}
+ (NSString *)DESEncryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *result = [self DESEncryptData:data keyString:keyString iv:iv];
// BASE 64 编码
return [result base64EncodedStringWithOptions:0];
}
#pragma mark 解密
+ (NSData *)DESDecryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv {
return [self CCCryptData:data algorithm:kCCAlgorithmDES operation:kCCDecrypt keyString:keyString iv:iv];
}
+ (NSString *)DESDecryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// BASE 64 解码
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
NSData *result = [self DESDecryptData:data keyString:keyString iv:iv];
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
#pragma mark - AES 加密/解密
#pragma mark 加密
+ (NSData *)AESEncryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv 	{
return [self CCCryptData:data algorithm:kCCAlgorithmAES operation:kCCEncrypt keyString:keyString iv:iv];
}
+ (NSString *)AESEncryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *result = [self AESEncryptData:data keyString:keyString iv:iv];
// BASE 64 编码
return [result base64EncodedStringWithOptions:0];
}
#pragma mark 解密
+ (NSData *)AESDecryptData:(NSData *)data keyString:(NSString *)keyString iv:(NSData *)iv {
return [self CCCryptData:data algorithm:kCCAlgorithmAES operation:kCCDecrypt keyString:keyString iv:iv];
}
+ (NSString *)AESDecryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// BASE 64 解码
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
NSData *result = [self AESDecryptData:data keyString:keyString iv:iv];
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
#pragma mark 对称加密&解密核心方法
///  对称加密&解密核心方法
///
///  @param data      加密/解密的二进制数据
///  @param algorithm 加密算法
///  @param operation 加密/解密操作
///  @param keyString 密钥字符串
///  @param iv        IV 向量
///
///  @return 加密/解密结果
+ (NSData *)CCCryptData:(NSData *)data algorithm:(CCAlgorithm)algorithm operation:(CCOperation)operation keyString:(NSString *)keyString iv:(NSData *)iv {
int keySize = (algorithm == kCCAlgorithmAES) ? kCCKeySizeAES128 : kCCKeySizeDES;
int blockSize = (algorithm == kCCAlgorithmAES) ? kCCBlockSizeAES128: kCCBlockSizeDES;
// 设置密钥
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:keySize];
// 设置 IV 向量
uint8_t cIv[blockSize];
bzero(cIv, blockSize);
int option = kCCOptionPKCS7Padding | kCCOptionECBMode;
if (iv) {
    [iv getBytes:cIv length:blockSize];
    option = kCCOptionPKCS7Padding;
}
// 设置输出缓冲区
size_t bufferSize = [data length] + blockSize;
void *buffer = malloc(bufferSize);
// 加密或解密
size_t cryptorSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(operation,
                                      algorithm,
                                      option,
                                      cKey,
                                      keySize,
                                      cIv,
                                      [data bytes],
                                      [data length],
                                      buffer,
                                      bufferSize,
                                      &cryptorSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
    result = [NSData dataWithBytesNoCopy:buffer length:cryptorSize];
} else {
    free(buffer);
    NSLog(@"[错误] 加密或解密失败 | 状态编码: %d", cryptStatus);
}
return result;
}
#pragma mark - RSA 加密/解密算法
- (void)loadPublicKeyWithFilePath:(NSString *)filePath; {
NSAssert(filePath.length != 0, @"公钥路径为空");
// 删除当前公钥
if (_publicKeyRef) CFRelease(_publicKeyRef);
// 从一个 DER 表示的证书创建一个证书对象
NSData *certificateData = [NSData dataWithContentsOfFile:filePath];
SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
NSAssert(certificateRef != NULL, @"公钥文件错误");
// 返回一个默认 X509 策略的公钥对象,使用之后需要调用 CFRelease 释放
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
// 包含信任管理信息的结构体
SecTrustRef trustRef;
// 基于证书和策略创建一个信任管理对象
OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
NSAssert(status == errSecSuccess, @"创建信任管理对象失败");
// 信任结果
SecTrustResultType trustResult;
// 评估指定证书和策略的信任管理是否有效
status = SecTrustEvaluate(trustRef, &trustResult);
NSAssert(status == errSecSuccess, @"信任评估失败");
// 评估之后返回公钥子证书
_publicKeyRef = SecTrustCopyPublicKey(trustRef);
NSAssert(_publicKeyRef != NULL, @"公钥创建失败");
if (certificateRef) CFRelease(certificateRef);
if (policyRef) CFRelease(policyRef);
if (trustRef) CFRelease(trustRef);
}
- (void)loadPrivateKey:(NSString *)filePath password:(NSString *)password {
NSAssert(filePath.length != 0, @"私钥路径为空");
// 删除当前私钥
if (_privateKeyRef) CFRelease(_privateKeyRef);
NSData *PKCS12Data = [NSData dataWithContentsOfFile:filePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
CFStringRef passwordRef = (__bridge CFStringRef)password;
// 从 PKCS #12 证书中提取标示和证书
SecIdentityRef myIdentity;
SecTrustRef myTrust;
const void *keys[] = {kSecImportExportPassphrase};
const void *values[] = {passwordRef};
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
// 返回 PKCS #12 格式数据中的标示和证书
OSStatus status = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
if (status == noErr) {
    CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
    myIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
    myTrust = (SecTrustRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
}
if (optionsDictionary) CFRelease(optionsDictionary);
NSAssert(status == noErr, @"提取身份和信任失败");
SecTrustResultType trustResult;
// 评估指定证书和策略的信任管理是否有效
status = SecTrustEvaluate(myTrust, &trustResult);
NSAssert(status == errSecSuccess, @"信任评估失败");
// 提取私钥
status = SecIdentityCopyPrivateKey(myIdentity, &_privateKeyRef);
NSAssert(status == errSecSuccess, @"私钥创建失败");
CFRelease(items);
}
- (NSString *)RSAEncryptString:(NSString *)string {
NSData *cipher = [self RSAEncryptData:[string dataUsingEncoding:NSUTF8StringEncoding]];
return [cipher base64EncodedStringWithOptions:0];
}
- (NSData *)RSAEncryptData:(NSData *)data {
OSStatus sanityCheck = noErr;
size_t cipherBufferSize = 0;
size_t keyBufferSize = 0;
NSAssert(data, @"明文数据为空");
NSAssert(_publicKeyRef, @"公钥为空");
NSData *cipher = nil;
uint8_t *cipherBuffer = NULL;
// 计算缓冲区大小
cipherBufferSize = SecKeyGetBlockSize(_publicKeyRef);
keyBufferSize = data.length;
if (kTypeOfWrapPadding == kSecPaddingNone) {
    NSAssert(keyBufferSize <= cipherBufferSize, @"加密内容太大");
} else {
    NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密内容太大");
}
// 分配缓冲区
cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0x0, cipherBufferSize);
// 使用公钥加密
sanityCheck = SecKeyEncrypt(_publicKeyRef,
                            kTypeOfWrapPadding,
                            (const uint8_t *)data.bytes,
                            keyBufferSize,
                            cipherBuffer,
                            &cipherBufferSize
                            );
NSAssert(sanityCheck == noErr, @"加密错误,OSStatus == %d", sanityCheck);
// 生成密文数据
cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
if (cipherBuffer) free(cipherBuffer);
return cipher;
}
- (NSString *)RSADecryptString:(NSString *)string {
NSData *keyData = [self RSADecryptData:[[NSData alloc] initWithBase64EncodedString:string options:0]];
return [[NSString alloc] initWithData:keyData encoding:NSUTF8StringEncoding];
}
- (NSData *)RSADecryptData:(NSData *)data {
OSStatus sanityCheck = noErr;
size_t cipherBufferSize = 0;
size_t keyBufferSize = 0;
NSData *key = nil;
uint8_t *keyBuffer = NULL;
SecKeyRef privateKey = _privateKeyRef;
NSAssert(privateKey != NULL, @"私钥不存在");
// 计算缓冲区大小
cipherBufferSize = SecKeyGetBlockSize(privateKey);
keyBufferSize = data.length;
NSAssert(keyBufferSize <= cipherBufferSize, @"解密内容太大");
// 分配缓冲区
keyBuffer = malloc(keyBufferSize * sizeof(uint8_t));
memset((void *)keyBuffer, 0x0, keyBufferSize);
// 使用私钥解密
sanityCheck = SecKeyDecrypt(privateKey,
                            kTypeOfWrapPadding,
                            (const uint8_t *)data.bytes,
                            cipherBufferSize,
                            keyBuffer,
                            &keyBufferSize
                            );
NSAssert1(sanityCheck == noErr, @"解密错误,OSStatus == %d", sanityCheck);
// 生成明文数据
key = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize];
if (keyBuffer) free(keyBuffer);
return key;
}
@end
二、OpenSSL 生成密钥示例~
生成强度是 1024 的 RSA 私钥
$ openssl genrsa -out private.pem 1024
执行以代码生成一个私钥,Pem文件,其实Pem文件就是一般的文本格式看下图
这是文件:
选择一个文本编辑器打开次文件可以看到其就是一个普通的文本:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCfwtWJLpe9QQiBOA/kDVdYGDYko6ieGfaIHiqiHd7Ul13k4gI+
1NgL6SfO/UAhKL6rAwTk9t8/V0bIrbCTBL6hMLc4yJkBFbDK7eLoJNnxaUwl2pLL
BSiTZQQ8vsBC6myUiZDFdCfl2PWvfEMzMYNsCob2Mw4MYWJwNub+MYe7PwIDAQAB
AoGAc8jXy5FKBa5BRK1lzujgWYdKjilSRisY4jPCwDWXzklZkk0+RV0qqw8ye7BN
LvsBnJ0Wif5lc9mEAmLnKtXwdWrHKEi70s69mZZH+ssaP3SGAEug3tY2ojSYixmB
+dWyslVb3dVzxr56fMJLfCBGAhqhmXgy79ruIbnKrDqo6kkCQQDPYCIZRlI0tREa
4y+E2YUqx/x6XPohlJUQoZBJQ3Zt0RQ+afljNxlSOiL4pw9GLwoDhatxzjlMUMnb
b36mP1plAkEAxTib34YEp5nkwpbZ5roAfKRmKgUnezULVCDKS/KiamXURwAUwGGU
aVy9o1akS48C42gsF+NtOe9yq1z9sj6y0wJBAICLZpekL3DcjC3OhbYj35gVPzva
RnJqV7xnabkASHjqEVJe/mexz9BYmTTo2V736Y0lXpC89GeJ7JZJFoiW3MECQDyM
4cZhpiIy7HoVyHa/GpEqBDfYd0OriHveyV1B9D2IYAEgdD6QdvlWQN7aJf0Q vklF
XWxEJe/IpUMZfMZx24MCQDu19hNYYg8863mvGbc7jWAY1Apjx1i/KTXe/6rBjmoS
bxoSEpKNHpW6dgL/6S6WQuB8j3tNUUNj5O99cU6DLsM=
-----END RSA PRIVATE KEY-----
接着跟着笔者一起执行下面的操作吧~
创建证书请求
$ openssl req -new -key private.pem -out rsacert.csr
这时候控制条要求输入以下一些个人信息那就跟着提示来吧
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:beijing
Locality Name (eg, city) []:beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Erma
Organizational Unit Name (eg, section) []:com
Common Name (e.g. server FQDN or YOUR name) []:Erma
Email Address []:mr_wangyaojie@163.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
这时候生成了一个csr文件
生成证书并且签名,有效期10年
$ openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
转换格式-将 PEM 格式文件转换成 DER 格式
$ openssl x509 -outform der -in rsacert.crt -out rsacert.der
导出P12文件
$ openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
最后生成了两个我们要用的文件,一个p12文件和一个der文件,der文件是公钥,p12文件是私钥。我们把这两个文件拖入我们的Demo中来使用吧下面是demo
三、der和p12加密解密Demo
通过这个Demo主要讲解上面提到的工具类的使用~
示例化工具类Tool
CryptorTools *tool = [[CryptorTools alloc] init];
1、加载公钥
NSString *pubPath = [[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil];
[tool loadPublicKeyWithFilePath:pubPath];
2、使用公钥加密
NSString *result = [tool RSAEncryptString:@"xiaoer"];
NSLog(@"%@",result);
3、加载私钥 - 密码是导出P12的密码
NSString *privatePath = [[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil];
[tool loadPrivateKey:privatePath password:@"xyz147896321"];
4、使用私钥解密
NSLog(@"%@", [tool RSADecryptString:result]);
OK上面是通过der和p12加密的应用过程下面再来看看字符串公钥加密的使用方法~
四、公钥字符串加密工具类~
RSA.h
//
//  RSA.h
//
//  Created by Erma on 15-2-3.
//  Copyright (c) 2015年 Erma. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RSA : NSObject
+ (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;
+ (NSString *)encryptData:(NSData *)data publicKey:(NSString *)pubKey;
@end
RSA.m
#import "RSA.h"
#import <Security/Security.h>
@implementation RSA
/*
static NSString *base64_encode(NSString *str){
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
if(!data){
	return nil;
}
return base64_encode_data(data);
}
*/
static NSString *base64_encode_data(NSData *data){
data = [data base64EncodedDataWithOptions:0];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return ret;
}
static NSData *base64_decode(NSString *str){
NSData *data = [[NSData alloc] initWithBase64EncodedString:str 	options:NSDataBase64DecodingIgnoreUnknownCharacters];
return data;
}
+ (NSData *)stripPublicKeyHeader:(NSData *)d_key{
// Skip ASN.1 public key header
if (d_key == nil) return(nil);
unsigned long len = [d_key length];
if (!len) return(nil);
unsigned char *c_key = (unsigned char *)[d_key bytes];
unsigned int  idx	 = 0;
if (c_key[idx++] != 0x30) return(nil);
if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;
// PKCS #1 rsaEncryption szOID_RSA_RSA
static unsigned char seqiod[] =
{ 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
	0x01, 0x05, 0x00 };
if (memcmp(&c_key[idx], seqiod, 15)) return(nil);
idx += 15;
if (c_key[idx++] != 0x03) return(nil);
if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;
if (c_key[idx++] != '\0') return(nil);
// Now make a new NSData from this buffer
return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}
//credit: http://hg.mozilla.org/services/fx-home/file/tip/Sources/NetworkAndStorage/	CryptoUtils.m#l1036
+ (NSData *)stripPrivateKeyHeader:(NSData *)d_key{
// Skip ASN.1 private key header
if (d_key == nil) return(nil);
unsigned long len = [d_key length];
if (!len) return(nil);
unsigned char *c_key = (unsigned char *)[d_key bytes];
unsigned int  idx	 = 22; //magic byte at offset 22
if (0x04 != c_key[idx++]) return nil;
//calculate length of the key
unsigned int c_len = c_key[idx++];
int det = c_len & 0x80;
if (!det) {
	c_len = c_len & 0x7f;
} else {
	int byteCount = c_len & 0x7f;
	if (byteCount + idx > len) {
		//rsa length field longer than buffer
		return nil;
	}
	unsigned int accum = 0;
	unsigned char *ptr = &c_key[idx];
	idx += byteCount;
	while (byteCount) {
		accum = (accum << 8) + *ptr;
		ptr++;
		byteCount--;
	}
	c_len = accum;
}
// Now make a new NSData from this buffer
return [d_key subdataWithRange:NSMakeRange(idx, c_len)];
}
+ (SecKeyRef)addPublicKey:(NSString *)key{
NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"];
NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"];
if(spos.location != NSNotFound && epos.location != NSNotFound){
	NSUInteger s = spos.location + spos.length;
	NSUInteger e = epos.location;
	NSRange range = NSMakeRange(s, e-s);
	key = [key substringWithRange:range];
}
key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@" "  withString:@""];
// This will be base64 encoded, decode it.
NSData *data = base64_decode(key);
data = [RSA stripPublicKeyHeader:data];
if(!data){
	return nil;
}
//a tag to read/write keychain storage
NSString *tag = @"RSAUtil_PubKey";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
[publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((__bridge CFDictionaryRef)publicKey);
// Add persistent version of the key to system keychain
[publicKey setObject:data forKey:(__bridge id)kSecValueData];
[publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
 kSecAttrKeyClass];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
 kSecReturnPersistentRef];
CFTypeRef persistKey = nil;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
if (persistKey != nil){
	CFRelease(persistKey);
}
if ((status != noErr) && (status != errSecDuplicateItem)) {
	return nil;
}
[publicKey removeObjectForKey:(__bridge id)kSecValueData];
[publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
if(status != noErr){
	return nil;
}
return keyRef;
}
+ (SecKeyRef)addPrivateKey:(NSString *)key{
NSRange spos;
NSRange epos;
spos = [key rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"];
if(spos.length > 0){
	epos = [key rangeOfString:@"-----END RSA PRIVATE KEY-----"];
}else{
	spos = [key rangeOfString:@"-----BEGIN PRIVATE KEY-----"];
	epos = [key rangeOfString:@"-----END PRIVATE KEY-----"];
}
if(spos.location != NSNotFound && epos.location != NSNotFound){
	NSUInteger s = spos.location + spos.length;
	NSUInteger e = epos.location;
	NSRange range = NSMakeRange(s, e-s);
	key = [key substringWithRange:range];
}
key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@" "  withString:@""];
// This will be base64 encoded, decode it.
NSData *data = base64_decode(key);
data = [RSA stripPrivateKeyHeader:data];
if(!data){
	return nil;
}
//a tag to read/write keychain storage
NSString *tag = @"RSAUtil_PrivKey";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init];
[privateKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
[privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((__bridge CFDictionaryRef)privateKey);
// Add persistent version of the key to system keychain
[privateKey setObject:data forKey:(__bridge id)kSecValueData];
[privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)
 kSecAttrKeyClass];
[privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
 kSecReturnPersistentRef];
CFTypeRef persistKey = nil;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey);
if (persistKey != nil){
	CFRelease(persistKey);
}
if ((status != noErr) && (status != errSecDuplicateItem)) {
	return nil;
}
[privateKey removeObjectForKey:(__bridge id)kSecValueData];
[privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef);
if(status != noErr){
	return nil;
}
return keyRef;
}
/* START: Encryption & Decryption with RSA private key */
+ (NSData *)encryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef{
const uint8_t *srcbuf = (const uint8_t *)[data bytes];
size_t srclen = (size_t)data.length;
size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
void *outbuf = malloc(block_size);
size_t src_block_size = block_size - 11;
NSMutableData *ret = [[NSMutableData alloc] init];
for(int idx=0; idx<srclen; idx+=src_block_size){
	//NSLog(@"%d/%d block_size: %d", idx, (int)srclen, (int)block_size);
	size_t data_len = srclen - idx;
	if(data_len > src_block_size){
		data_len = src_block_size;
	}
	size_t outlen = block_size;
	OSStatus status = noErr;
	status = SecKeyEncrypt(keyRef,
						   kSecPaddingPKCS1,
						   srcbuf + idx,
						   data_len,
						   outbuf,
						   &outlen
						   );
	if (status != 0) {
		NSLog(@"SecKeyEncrypt fail. Error Code: %d", status);
		ret = nil;
		break;
	}else{
		[ret appendBytes:outbuf length:outlen];
	}
}
free(outbuf);
CFRelease(keyRef);
return ret;
}
+ (NSString *)encryptString:(NSString *)str privateKey:(NSString *)privKey{
NSData *data = [RSA encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] privateKey:privKey];
NSString *ret = base64_encode_data(data);
return ret;
}
+ (NSData *)encryptData:(NSData *)data privateKey:(NSString *)privKey{
if(!data || !privKey){
	return nil;
}
SecKeyRef keyRef = [RSA addPrivateKey:privKey];
if(!keyRef){
	return nil;
}
return [RSA encryptData:data withKeyRef:keyRef];
}
+ (NSData *)decryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef{
const uint8_t *srcbuf = (const uint8_t *)[data bytes];
size_t srclen = (size_t)data.length;
size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
UInt8 *outbuf = malloc(block_size);
size_t src_block_size = block_size;
NSMutableData *ret = [[NSMutableData alloc] init];
for(int idx=0; idx<srclen; idx+=src_block_size){
	//NSLog(@"%d/%d block_size: %d", idx, (int)srclen, (int)block_size);
	size_t data_len = srclen - idx;
	if(data_len > src_block_size){
		data_len = src_block_size;
	}
	size_t outlen = block_size;
	OSStatus status = noErr;
	status = SecKeyDecrypt(keyRef,
						   kSecPaddingNone,
						   srcbuf + idx,
						   data_len,
						   outbuf,
						   &outlen
						   );
	if (status != 0) {
		NSLog(@"SecKeyEncrypt fail. Error Code: %d", status);
		ret = nil;
		break;
	}else{
		//the actual decrypted data is in the middle, locate it!
		int idxFirstZero = -1;
		int idxNextZero = (int)outlen;
		for ( int i = 0; i < outlen; i++ ) {
			if ( outbuf[i] == 0 ) {
				if ( idxFirstZero < 0 ) {
					idxFirstZero = i;
				} else {
					idxNextZero = i;
					break;
				}
			}
		}
		[ret appendBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1];
	}
}
free(outbuf);
CFRelease(keyRef);
return ret;
}
+ (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey{
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
data = [RSA decryptData:data privateKey:privKey];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return ret;
}
+ (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privKey{
if(!data || !privKey){
	return nil;
}
SecKeyRef keyRef = [RSA addPrivateKey:privKey];
if(!keyRef){
	return nil;
}
return [RSA decryptData:data withKeyRef:keyRef];
}
/* END: Encryption & Decryption with RSA private key */
/* START: Encryption & Decryption with RSA public key */
+ (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey{
NSData *data = [RSA encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey];
NSString *ret = base64_encode_data(data);
return ret;
}
+ (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{
if(!data || !pubKey){
	return nil;
}
SecKeyRef keyRef = [RSA addPublicKey:pubKey];
if(!keyRef){
	return nil;
}
return [RSA encryptData:data withKeyRef:keyRef];
}
+ (NSString *)decryptString:(NSString *)str publicKey:(NSString *)pubKey{
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
data = [RSA decryptData:data publicKey:pubKey];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return ret;
}
+ (NSData *)decryptData:(NSData *)data publicKey:(NSString *)pubKey{
if(!data || !pubKey){
	return nil;
}
SecKeyRef keyRef = [RSA addPublicKey:pubKey];
if(!keyRef){
	return nil;
}
return [RSA decryptData:data withKeyRef:keyRef];
}
/* END: Encryption & Decryption with RSA public key */
@end
五、公钥加密Demo
次示例是适用于连个场景,服务器返回一个公钥字符串到iOS客户端,还有一种就是博客园官方接口给的公钥加密大多数读者找到这里的时候都是因为服务器返回一个公钥字符串如何加密来到这里的吧下面看demo代码~
一、加载公钥字符窜,本处隐藏,因为保密~
NSString *publicKey = @"YourPublicKey";
二、对账号密码加密~
NSString *name = [RSA encryptString:@"你的账号" publicKey:publicKey];
NSString *password = [RSA encryptString:@"你的密码" publicKey:publicKey];
三、OK,打印出来看看吧~
NSLog(@"%@",name);
NSLog(@"%@",password);
这个Demo很简单不过在做RSA机密的时候遇到了一个问题,看下面
六、一个关于RSA加密困扰了我几天的问题~
这个问题困扰了笔者好几天之前一直以为是工具类代码有问题尝试了换了各种工具,自己也写了一个工具类,还是不成功我在请求博客园官方的服务器一直返回一下错误一个字符串贴出来看看,错误字符串如下
<!DOCTYPE html>
<html>
<head>
    <title>Base-64 字符数组或字符串的长度无效。</title>
    <meta name="viewport" content="width=device-width" />
    <style>
     body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}
     p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
     b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
     H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
     H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
     pre {font-family:"Consolas","Lucida Console",Monospace;font-size:11pt;margin:0;padding:0.5em;line-height:14pt}
     .marker {font-weight: bold; color: black;text-decoration: none;}
     .version {color: gray;}
     .error {margin-bottom: 10px;}
     .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
     @media screen and (max-width: 639px) {
      pre { width: 440px; overflow: auto; white-space: pre-wrap; word-wrap: break-word; }
     }
     @media screen and (max-width: 479px) {
      pre { width: 280px; }
     }
    </style>
</head>
<body bgcolor="white">
        <span><H1>“/”应用程序中的服务器错误。<hr width=100% size=1 color=silver></H1>
        <h2> <i>Base-64 字符数组或字符串的长度无效。</i> </h2></span>
        <font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">
        <b> 说明: </b>执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
        <br><br>
        <b> 异常详细信息: </b>System.FormatException: Base-64 字符数组或字符串的长度无效。<br><br>
        <b>源错误:</b> <br><br>
        <table width=100% bgcolor="#ffffcc">
           <tr>
              <td>
                  <code>
执行当前 Web 请求期间生成了未经处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。</code>
              </td>
           </tr>
        </table>
        <br>
        <b>堆栈跟踪:</b> <br><br>
        <table width=100% bgcolor="#ffffcc">
           <tr>
              <td>
                  <code><pre>
[FormatException: Base-64 字符数组或字符串的长度无效。]
System.Convert.FromBase64_Decode(Char* startInputPtr, Int32 inputLength, Byte* startDestPtr, Int32 destLength) +307
System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) +152
System.Convert.FromBase64String(String s) +49
CNBlogs.Infrastructure.Common.RSACryptoService.Decrypt(String cipherText) +40
OpenAPI.Providers.<GrantResourceOwnerCredentials>d__5.MoveNext() +412
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
	 Microsoft.Owin.Security.OAuth.<InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantA sync>d__3f.MoveNext() +700
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +13848037
Microsoft.Owin.Security.OAuth.<InvokeTokenEndpointAsync>d__22.MoveNext() +1933
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
Microsoft.Owin.Security.OAuth.<InvokeAsync>d__0.MoveNext() +1211
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +540
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +203
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +193
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +96
System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +363
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137
              </td>
           </tr>
        </table>
        <br>
        <hr width=100% size=1 color=silver>
        <b>版本信息:</b> Microsoft .NET Framework 版本:4.0.30319; ASP.NET 版本:4.6.1055.0
        </font>
</body>
</html>
把这个html的编译为网页后打开看到如下效果图

笔者在第一次请求的时候就遇到了同样的问题一直怀疑是加密工具有误所以多次尝试更换加密工具还是不成功最后我发现了错误原因~
加密后的字符串中的"+"通过地址栏传过来时,后台会解析为空格. 最好的做法是 使用String.Replace("+", "%2B")先将空格编码,然后再作为参数传给另一页面传递,这样页面在提取参数时才会将“%2B”解码为加号.但这儿为了简化,将空格直接还原为"+"。
参考
DES解密时“Base-64字符数组的无效长度”
问题是 在页面传送的时候加密了 ,然后解密出来就抛出异常  跟踪发现是 ++ 在解析REQUEST的时候变成了空格
解决办法
使用String.Replace("+", "%2B")先将空格编码,然后再作为参数传给另一页面传递,这样页面在提取参数时才会将“%2B”解码为加号
下面是一个相关的知识
在使用Convert.ToBase64String()对字符串进行Base64编码时,注意的几点:
例:string s = "Hello";
byte[] bytes = Convert.FromBase64String(s);
以上代码在运行时会抛出FormatException异常.提示为:Base-64字符数组的无效长度
原因:
当Convert.FromBase64String方法的参数s的长度小于4或不是4的偶数倍时,将会抛出FormatException。
例:
Convert.FromBase64String("Hell");      // Normal.
Convert.FromBase64String("Hell ");     // Normal.(忽略空格)
Convert.FromBase64String("Hello!");     // throw FormatException.
Convert.FromBase64String("Hello Net"); // Normal.(忽略空格)
最终的解决办法~
把加密后的字符串中有+号的地方全部换为%2B,代码如下~
name = [name stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
password = [password stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
OK本文记录的是笔者对RSA应用的总结
基于OpenSSL的RSA加密应用(非算法)的更多相关文章
- 基于OpenSLL的RSA加密应用(非算法)
		
基于OpenSLL的RSA加密应用(非算法) iOS开发中的小伙伴应该是经常用der和p12进行加密解密,而且在通常加密不止一种加密算法,还可以加点儿盐吧~本文章主要阐述的是在iOS中基于openSL ...
 - 利用openssl进行RSA加密解密
		
openssl是一个功能强大的工具包,它集成了众多密码算法及实用工具.我们即可以利用它提供的命令台工具生成密钥.证书来加密解密文件,也可以在利用其提供的API接口在代码中对传输信息进行加密. RSA是 ...
 - openssl evp RSA 加密解密
		
openssl evp RSA 加密解密 可以直接使用RSA.h 提供的接口 如下测试使用EVP提供的RSA接口 1. EVP提供的RSA 加密解密 主要接口: int EVP_PKEY_encryp ...
 - OpenSSL 中 RSA 加密解密实现源代码分析
		
1.RSA 公钥和私钥的组成.以及加密和解密的公式: 2.模指数运算: 先做指数运算,再做模运算.如 5^3 mod 7 = 125 mod 7 = 6 3.RSA加密算法流程: 选择一对不同的.而且 ...
 - 用openssl库RSA加密解密
		
#include <stdio.h> #include <openssl/rsa.h> #include <openssl/pem.h> #include < ...
 - JAVA实现RSA加密解密  非对称算法
		
首先RSA是一个非对称的加密算法.所以在使用该算法加密解密之前,必须先行生成密钥对.包含公钥和私钥 JDK中提供了生成密钥对的类KeyPairGenerator,实比例如以下: public stat ...
 - 利用Openssl进行RSA加密签名算法
		
加密(签名)的过程是(M的e次方)mod n,在这里我们把消息M假定为一个数字,但实际上消息一般为字符串,所以必须有一个将字符串转化为数字的规则,并且要让这个数字的大小和n相当(也不能比 n大).这样 ...
 - jsencrypt代码分析——openssl的rsa加密解密在js的实现
		
在js上做rsa,感觉jsencrypt这个是封装的比较好的,但用起来还是遇到了些坑,所以踩进代码里填填坑- 项目在这里 https://github.com/travist/jsencrypt [r ...
 - php使用openssl进行Rsa长数据加密(117)解密(128) 和 DES 加密解密
		
PHP使用openssl进行Rsa加密,如果要加密的明文太长则会出错,解决方法:加密的时候117个字符加密一次,然后把所有的密文拼接成一个密文:解密的时候需要128个字符解密一下,然后拼接成数据. 加 ...
 
随机推荐
- vim在插入模式粘贴代码缩进问题解决方法
			
转载自:https://blog.csdn.net/commshare/article/details/6215088 在vim粘贴代码会出现缩进问题,原因在于vim在代码粘贴时会自动缩进 解决方法: ...
 - Kali-linux系统指纹识别
			
现在一些便携式计算机操作系统使用指纹识别来验证密码进行登录.指纹识别是识别系统的一个典型模式,包括指纹图像获取.处理.特征提取和对等模块.如果要做渗透测试,需要了解要渗透测试的操作系统的类型才可以.本 ...
 - 软件分享:将应用一键打包成dmg文件
			
简介 苹果软件开发完成后,都要打包成dmg文件.通常的做法也许是到系统自带的磁盘工具里制作dmg文件,但这样做比较繁琐,尤其是要打包多个应用时,每次只能制作一个dmg文件很麻烦.分享一个很好用很方便的 ...
 - PHP面试系列 之Linux(六)---- 面试题整理
			
1.shell命令 top:查看有哪些系统进程正在运行.该命令提供了实时对系统处理器状态的监控,它能够实时显示系统中各个进程的资源占用情况.该命令可以按照对CPU.内存使用和执行时间对系统任务进程进行 ...
 - shell一次性执行多条命令
			
1.每个命令之间用;隔开说明:各命令的执行给果,不会影响其它命令的执行.换句话说,各个命令都会执行,但不保证每个命令都执行成功. 2.每个命令之间用&&隔开说明:若前面的命令执行成功, ...
 - postman请求失败
			
注意右上角 我点亮了左边的图标,导致任何请求都没法获取到结果,后来知道是右上角的问题,然后就可以成功请求了
 - 关于ie8下监听input事件的不兼容问题。
			
关于在ie8下,监听输入框的值变化的input事件不支持的解决办法: 很懒...直接上原文地址.... 原文地址:http://www.cnblogs.com/lhb25/archive/2012/1 ...
 - linux内核中网络文件系统的注册初始化
			
针对内核3.9 系统开启时,会使用init/main.c,然后再里面调用kernel_init(),在里面会再调用do_basic_setup(),调用do_initcalls(),调用do_one_ ...
 - Android性能监控
			
Android性能监控 一.搭建Android性能测试环境,参见<Android性能测试之Monkey使用>中内容. 二.启动Android虚拟机,可以通过eclipse启动,也可以通过命 ...
 - linux的虚拟文件系统VFS
			
虚拟文件系统(virtual file system),别名虚拟文件系统开关,是linux中的一个软件层,向用户空间提供文件系统操作接口. VFS包含的系统调用包括open(2).stat(2).re ...