![](/img/trans.png)
[英]how to encrypt and decrypt a String(Plain Text) with RSA public key in ios, swift
[英]encrypt or sign string with public key in iOS with Objective C
我有一个私钥。 以“ ---开始私钥...”开头的文本文件
我想使用该密钥来加密NSString。 由于它是私钥,因此最好将其签名为NSString。
没有任何外部框架就能做到吗?
结果应等于php openssl_sign函数。
您将需要使用的iOS SDK框架称为
CommonCrypto
。
这是一篇很好的
文章 ,描述了正确的解决方法。
编辑:我错过了有关与PHP函数openssl_sign
兼容性的部分。 下面的解决方案可以解决该问题。
使其与PHP函数openssl_sign
兼容的openssl_sign
是使用OpenSSL库。 openssl_sign
函数在内部使用OpenSSL的EVP API来使用私钥对输入字符串进行加密,并计算该加密字符串的SHA-1哈希摘要。 然后,通常将此哈希摘要转换为Base64编码的字符串。
不幸的是,iOS SDK不包含OpenSSL,但构建起来很容易。 以下关于为iOS构建OpenSSL的说明摘自该博客文章,并在此处转载以提供该问题的完整解决方案。
在终端中,按照以下步骤构建适用于iOS的OpenSSL库:
# Make a directory in which to run the build
mkdir ~/openssl-ios
cd ~/openssl-ios
# Download the openssl source (verify the file before using it in production!)
curl -O http://www.openssl.org/source/openssl-1.0.1e.tar.gz
# Download the openssl iOS build script
curl -O https://raw.github.com/Raphaelios/raphaelios-scripts/master/openssl/build-openssl.sh
# Make the build script executable
chmod +x build-openssl.sh
# Run the script (takes about 3min on an Intel Core i5)
./build-openssl.sh
这将需要几分钟,但是一旦完成,您可以使用以下命令验证构建库是否为通用库,您可以在iOS设备和iOS Simulator中使用它:
lipo -info ~/openssl-ios/lib/*.a
现在已经建立了OpenSSL库,让我们继续编写代码以对字符串进行签名。
首先,我们需要设置Xcode项目以链接到OpenSSL库。 将libcrypto.a
和libssl.a
都libssl.a
到iOS项目的项目导航器中的Frameworks组中。 在项目的Build Settings中 ,将以下内容添加到Header Search Paths设置:
~/openssl-ios/include/include
接下来,在NSString
类上创建一个名为openssl_sign
的新Objective-C Category
文件。 在NSString+openssl_sign.h
,定义以下接口:
@interface NSString (openssl_sign)
- (NSString *)signStringWithPrivateKey:(NSData *)privateKey;
@end
在NSString+openssl_sign.m
,添加以下标头导入:
#import <openssl/evp.h>
#import <openssl/pem.h>
并添加以下signStringWithPrivateKey:
实现:
@implementation NSString (openssl_sign)
- (NSString *)signStringWithPrivateKey:(NSData *)privateKeyData
{
BIO *publicBIO = NULL;
EVP_PKEY *privateKey = NULL;
if ((publicBIO = BIO_new_mem_buf((unsigned char *)[privateKeyData bytes], [privateKeyData length])) == NO) {
NSLog(@"BIO_new_mem_buf() failed!");
return nil;
}
if (PEM_read_bio_PrivateKey(publicBIO, &privateKey, NULL, NULL) == NO) {
NSLog(@"PEM_read_bio_PrivateKey() failed!");
return nil;
}
const char * cString = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned int stringLength = [self length];
unsigned char * signatureBuffer[EVP_MAX_MD_SIZE];
int signatureLength;
EVP_MD_CTX msgDigestContext;
const EVP_MD * msgDigest = EVP_sha1();
EVP_MD_CTX_init(&msgDigestContext);
EVP_SignInit(&msgDigestContext, msgDigest);
EVP_SignUpdate(&msgDigestContext, cString, stringLength);
if (EVP_SignFinal(&msgDigestContext, (unsigned char *)signatureBuffer, (unsigned int *)&signatureLength, privateKey) == NO) {
NSLog(@"Failed to sign string.");
return nil;
}
EVP_MD_CTX_cleanup(&msgDigestContext);
EVP_PKEY_free(privateKey);
NSData *signatureData = [NSData dataWithBytes:signatureBuffer length:signatureLength];
NSString *signature = [signatureData base64EncodedStringWithOptions:0];
return signature;
}
@end
在将对字符串进行签名的类中,您现在可以导入NSString+openssl_sign.h
并对字符串进行签名,如下所示:
NSData *privateKey = ...; // Read the .pem file into a NSData variable
NSString *helloSignature = [@"hello" signStringWithPrivateKey:privateKey];
您可以在终端中使用以下命令来验证签名是否相同:
echo -n "hello" | openssl dgst -sha1 -sign priv.pem | openssl enc -base64 | tr -d '\n'
您无需外部资源或组件即可轻松解决此问题。
我发现了方法并想与他人分享,以便我可以帮助他人。
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:privateKeyResourceName ofType:@"p12"]; NSData *p12Data = [NSData dataWithContentsOfFile:resourcePath]; NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; SecKeyRef privateKeyRef = NULL; //change to the actual password you used here [options setObject:@"_YOURPASSWORDHERE__" forKey:(__bridge id)kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items); if (securityError == noErr && CFArrayGetCount(items) > 0) { CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef); if (securityError != noErr) { privateKeyRef = NULL; } } CFRelease(items); privateKey = privateKeyRef; maxPlainLen = SecKeyGetBlockSize(privateKey) - 12;
- (NSData*)toSha1AsData { // PHP uses ASCII encoding, not UTF const char *s = [self cStringUsingEncoding:NSASCIIStringEncoding]; NSData *keyData = [NSData dataWithBytes:s length:strlen(s)]; // This is the destination uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; // This one function does an unkeyed SHA1 hash of your hash data CC_SHA1(keyData.bytes, keyData.length, digest); // Now convert to NSData structure to make it usable again NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH] return out; }
(NSData *)signSha1Data:(NSData *)data {
size_t plainLen = [data length];
if (plainLen > maxPlainLen)
{
NSLog(@"content(%ld) is too long, must < %ld", plainLen, maxPlainLen);
return nil;
}
void *plain = malloc(plainLen);
[data getBytes:plain
length:plainLen];
size_t cipherLen = 128; // currently RSA key length is set to 128 bytes
void *cipher = malloc(cipherLen);
OSStatus returnCode = SecKeyRawSign(privateKey, kSecPaddingPKCS1SHA1,
plain, plainLen, cipher, &cipherLen);
NSData *result = nil;
if (returnCode != 0) {
NSLog(@"SecKeyEncrypt fail. Error Code: %ld", returnCode);
}
else {
result = [NSData dataWithBytes:cipher
length:cipherLen];
}
free(plain);
free(cipher);
return result;
}
它运行良好,没有任何外部库。 无需编译一些奇怪的openssl东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.