RSA是目前最有影響力的公鑰加密算法,該算法基于一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰,即公鑰,而兩個大素數組合成私鑰。公鑰是可發布的供任何人使用,私鑰則為自己所有,供解密之用。
RSA加密算法
支付寶提供的Demo執行流程如下:
(僅作理解之用,里面還涉及OpenSSL相關文件的調用,暫時不具體分析)
step1:給訂單對象Oder各屬性賦值,改寫Oder的description方法,拼接訂單信息字符串。
//將商品信息賦予AlixPayOrder的成員變量
Order *order = [[Order alloc] init];
order.partner = partner;
order.seller = seller;
#warning TODO:服務器提供相關交易信息
order.tradeNO = [self generateTradeNO]; //訂單ID(由商家自行制定)
order.productName = self.product.subject; //商品標題
order.productDescription = self.product.body; //商品描述
order.amount = [NSString stringWithFormat:@"%.2f",self.product.price]; //商品價格
order.notifyURL = @"http://www.xxx.com"; //回調URL
order.service = @"mobile.securitypay.pay";
order.paymentType = @"1"; //默認是1
order.inputCharset = @"utf-8";
order.itBPay = @"30m"; //訂單過期時間30分鐘
order.showUrl = @"m.alipay.com";
//將商品信息拼接成字符串
NSString *orderSpec = [order description];
step2:用私鑰生成簽名器signer
//獲取私鑰并將商戶信息簽名,外部商戶可以根據情況存放私鑰和簽名,只需要遵循RSA簽名規范,并將簽名字符串base64編碼和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
//所調用的工廠方法
id<DataSigner> CreateRSADataSigner(NSString *privateKey) {
return [[RSADataSigner alloc] initWithPrivateKey:privateKey];
}
//所調用的初始化方法
- (id)initWithPrivateKey:(NSString *)privateKey {
if (self = [super init]) {
_privateKey = [privateKey copy];
}
return self;
}
step3:給訂單信息生成簽名
NSString *signedString = [signer signString:orderSpec];
//該簽名方法僅供參考,外部商戶可用自己方法替換
- (NSString *)signString:(NSString *)string {
//在Document文件夾下創建私鑰文件
NSString *signedString = nil;
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [documentPath stringByAppendingPathComponent:@"AlixPay-RSAPrivateKey"];
//把密鑰寫入文件
NSString *formatKey = [self formatPrivateKey:_privateKey];
[formatKey writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding];
int messageLength = strlen(message);
unsigned char *sig = (unsigned char *)malloc(256);
unsigned int sig_len;
//該方法為 openssl_wrapper.h中的方法
int ret = rsa_sign_with_private_key_pem((char *)message, messageLength, sig, &sig_len, (char *)[path UTF8String]);
//簽名成功,需要給簽名字符串base64編碼和UrlEncode,該兩個方法也可以根據情況替換為自己函數
if (ret == 1) {
NSString *base64String = base64StringFromData([NSData dataWithBytes:sig length:sig_len]);
//NSData *UTF8Data = [base64String dataUsingEncoding:NSUTF8StringEncoding];
signedString = [self urlEncodedString:base64String];
}
free(sig);
return signedString;
}
格式化?私鑰
- (NSString *)formatPrivateKey:(NSString *)privateKey {
const char *pstr = [privateKey UTF8String];
int len = [privateKey length];
NSMutableString *result = [NSMutableString string];
[result appendString:@"-----BEGIN PRIVATE KEY-----\n"];
int index = 0;
int count = 0;
while (index < len) {
char ch = pstr[index];
if (ch == '\r' || ch == '\n') {
++index;
continue;
}
[result appendFormat:@"%c", ch];
if (++count == 79) {
[result appendString:@"\n"];
count = 0;
}
index++;
}
[result appendString:@"\n-----END PRIVATE KEY-----"];
return result;
}