[英]Sign a string with an RSA private key
In my app i have to sign a message with an RSA private key i already have. 在我的应用程序中,我必须使用已经拥有的RSA私钥对消息签名。 After this done, i want to use the signature later. 完成此操作后,我想稍后使用签名。 I've checked several libraries, but all of them do much more that i need. 我已经检查了几个库,但是它们都做了很多我需要做的事情。 This is what i'd like to do: 这就是我想做的:
NSString *message = @"This is a message";
NSString *privateKey = ...;
NSString *signature = [self signMessage:message withPrivateKey:privateKey];
How would 怎么会
(NSString *)signMessage:(NSString *)message withPrivateKey:(NSString *)privateKey {
}
look like? 看起来像?
iOS has a C API for doing this. iOS具有执行此操作的C API。 I've never used it myself, but it looks like you need a PKCS12 formatted file with the private key in it which you import with SecKeyPKCS12Imort and get the private key out of. 我自己从未使用过它,但是看起来您需要一个包含私钥的PKCS12格式的文件,您可以使用SecKeyPKCS12Imort导入该文件并取出私钥。 Then the function is SecKeyRawSign to sign your string. 然后,该函数是SecKeyRawSign以对您的字符串进行签名。
The string should first be converted to an NSData object using a known character encoding - probably UTF-8 and the bytes in the NSData signed. 首先应使用已知的字符编码将字符串转换为NSData对象-可能为UTF-8,并对NSData中的字节进行签名。
If you use non-ASCII characters in your string, as well as making sure you use a well defined encoding, you also need to be careful of how some characters are represented. 如果在字符串中使用非ASCII字符,并确保使用定义良好的编码,则还需要注意某些字符的表示方式。 For instance é can be represented as a single Unicode number or as the Unicode acute accent followed by the letter e. 例如,é可以表示为单个Unicode数字,也可以表示为Unicode重音符号,后跟字母e。
http://en.wikipedia.org/wiki/Precomposed_character http://en.wikipedia.org/wiki/Precomposed_character
I've tried millions of signing methods, that include Keychain, extracting SecKeyRef's, certificates (.p12), .pem key-files, but still didn't manage to achieve my main goal: 我已经尝试了数百万种签名方法,包括钥匙串,提取SecKeyRef,证书(.p12)、. pem密钥文件,但仍然无法实现我的主要目标:
My private key is a PKCS#1 private key formatted like this: 我的私钥是一个格式如下的PKCS#1私钥:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCx9YWznzT3irAArr+INM5m0i6UCNICq4E8yrWwPbGh8/kdU/oh
..... ..... ..... ..... ..... ..... ..... .....
eF9lWooBNGgSh5vmkgECQGJwmDLKohSKEtVwGOIp3S3j+CHs0vVnznmtmC9sfrj4
ef48Sx1KFI8iQa3Nfv5bokaJkiIVVx/eMaa96Vracjc=
-----END RSA PRIVATE KEY-----
Eventually I moved to OpenSSL and things got much brighter. 最终,我搬到了OpenSSL,事情变得更加光明。 So the whole process looks like the following: 因此,整个过程如下所示:
Download the library from https://github.com/x2on/OpenSSL-for-iPhone 从https://github.com/x2on/OpenSSL-for-iPhone下载该库
Copy build-libssl.sh to your project folder Using Terminal run the following: 将build-libssl.sh复制到您的项目文件夹中使用Terminal运行以下命令:
cd [your project folder]
/build-libssl.sh
Copy the “include” folder from OpenSSL into your project-folder 将OpenSSL中的“ include”文件夹复制到您的项目文件夹中
Drag-copy the libcrypto*.a and libss*.a files into your XCode Folder 将libcrypto * .a和libss * .a文件拖放到XCode文件夹中
Open the Build Settings of your “Target” 打开“目标”的构建设置
Change Library Search Paths
to $(inherited) “$(SRCROOT)”
将Library Search Paths
更改为$(inherited) “$(SRCROOT)”
Change User Header Search Paths
to include
更改User Header Search Paths
以include
Activate Always Search User Paths
激活Always Search User Paths
#include <openssl/pem.h>
#include <openssl/engine.h>
#include <iomanip>
- (NSString*) signHeader:(NSString*) pTextString withPrivateKey: (NSString*) pPrivateKey {
int retEr;
char* text = (char*) [pTextString UTF8String];
unsigned char *data;
unsigned int dataLen;
// converting nsstring base64 private key to openssl RSA key
BIO *mem = NULL;
RSA *rsa_private = NULL;
char *private_key = (char*)[pPrivateKey UTF8String];
mem = BIO_new_mem_buf(private_key, strlen(private_key));
if (mem == NULL)
{
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
fprintf(stderr, "OpenSSL error: %s", buffer);
exit(0);
}
rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL);
BIO_free (mem);
if (rsa_private == NULL)
{
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
fprintf(stderr, "OpenSSL error: %s", buffer);
exit(0);
}
// end of convertion
data = (unsigned char *) text;
dataLen = strlen(text);
//// creating signature
// sha1
unsigned char hash[SHA_DIGEST_LENGTH];
unsigned char sign[128];
unsigned int signLen;
SHA1(data, dataLen, hash);
// signing
retEr = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sign, &signLen, rsa_private);
// printf("Signature len gth = %d\n", signLen);
printf("RSA_sign: %s\n", (retEr == 1) ? "RSA_sign success" : "RSA_sign error");
// convert unsigned char -> std:string
std::stringstream buffer;
for (int i = 0; i < 128; i++)
{
buffer << std::hex << std::setfill('0');
buffer << std::setw(2) << static_cast<unsigned>(sign[i]);
}
std::string signature = buffer.str();
// convert std:string -> nsstring
NSString *signedMessage = [NSString stringWithCString:signature.c_str() encoding:[NSString defaultCStringEncoding]];
RSA_free(rsa_private);
return signedMessage;
}
If you want to use SHA256 or any other SHA you must change the following: 如果要使用SHA256或任何其他SHA,则必须更改以下内容:
SHA_DIGEST_LENGTH => SHA256_DIGEST_LENGTH
sign[128] => sign[256]
SHA1(data, dataLen, hash) => SHA256(data, dataLen, hash)
NID_sha1 => NID_sha256
Since Swift language isn't a superset of C++ it can't be combined with C++ directly, therefore you need to create a Objective-C wrapper of C++ code and then call it (Obj-C) from your Swift code. 由于Swift语言不是C ++的超集,因此不能直接与C ++组合,因此您需要创建一个C ++代码的Objective-C包装器,然后从您的Swift代码中调用它(Obj-C)。
Create an Obj-C class for your C++ code. 为您的C ++代码创建一个Obj-C类。 IMPORTANT: the file must be either with .mm extension or set type to Objective-C++ Source
重要说明:该文件必须具有.mm扩展名或将类型设置为Objective-C++ Source
OpenSSLWrapper.h OpenSSLWrapper.h
#import <Foundation/Foundation.h>
@interface OpenSSLWrapper : NSObject
+ (NSString*) signHeader:(NSString*) pTextString withPrivateKey: (NSString*) pPrivateKey;
@end
OpenSSLWrapper.mm OpenSSLWrapper.mm
#import "OpenSSLWrapper.h"
#include <openssl/pem.h>
#include <openssl/engine.h>
#include <iomanip>
@implementation OpenSSLWrapper
+ (NSString*) signHeader:(NSString*) pTextString withPrivateKey: (NSString*) pPrivateKey {
int retEr;
char* text = (char*) [pTextString UTF8String];
unsigned char *data;
unsigned int dataLen;
// converting nsstring base64 private key to openssl RSA key
BIO *mem = NULL;
RSA *rsa_private = NULL;
char *private_key = (char*)[pPrivateKey UTF8String];
mem = BIO_new_mem_buf(private_key, strlen(private_key));
if (mem == NULL)
{
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
fprintf(stderr, "OpenSSL error: %s", buffer);
exit(0);
}
rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL);
BIO_free (mem);
if (rsa_private == NULL)
{
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
fprintf(stderr, "OpenSSL error: %s", buffer);
exit(0);
}
// end of convertion
data = (unsigned char *) text;
dataLen = strlen(text);
//// creating signature
// sha1
unsigned char hash[SHA_DIGEST_LENGTH];
unsigned char sign[128];
unsigned int signLen;
SHA1(data, dataLen, hash);
// signing
retEr = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sign, &signLen, rsa_private);
// printf("Signature len gth = %d\n", signLen);
printf("RSA_sign: %s\n", (retEr == 1) ? "RSA_sign success" : "RSA_sign error");
// convert unsigned char -> std:string
std::stringstream buffer;
for (int i = 0; i < 128; i++)
{
buffer << std::hex << std::setfill('0');
buffer << std::setw(2) << static_cast<unsigned>(sign[i]);
}
std::string signature = buffer.str();
// convert std:string -> nsstring
NSString *signedMessage = [NSString stringWithCString:signature.c_str() encoding:[NSString defaultCStringEncoding]];
RSA_free(rsa_private);
return signedMessage;
}
@end
Create a Bridging-Header file. 创建一个桥接头文件。
YourProject-Bridging-Header.h YourProject桥接,Header.h
#import "OpenSSLWrapper.h"
Use the method from Obj-C in your Swift file. 在您的Swift文件中使用Obj-C中的方法。
DigestSignature.swift DigestSignature.swift
import Cocoa
class DigestSignature: NSObject {
let privateKey = "-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQCx9YWznzT3irAArr+INM5m0i6UCNICq4E8yrWwPbGh8/kdU/oh ..... ..... eF9lWooBNGgSh5vmkgECQGJwmDLKohSKEtVwGOIp3S3j+CHs0vVnznmtmC9sfrj4ef48Sx1KFI8iQa3Nfv5bokaJkiIVVx/eMaa96Vracjc=-----END RSA PRIVATE KEY-----"
var digest: String = OpenSSLWrapper.signHeader("Hello World", withPrivateKey: privateKey) ;
}
Hope that helps 希望能有所帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.