使用RSA私钥签名string

在我的应用程序中,我必须用我已有的RSA私钥签名消息。 完成后,我想稍后使用签名。 我检查了几个图书馆,但他们都做了更多,我需要。 这是我想要做的:

NSString *message = @"This is a message"; NSString *privateKey = ...; NSString *signature = [self signMessage:message withPrivateKey:privateKey]; 

怎么会

 (NSString *)signMessage:(NSString *)message withPrivateKey:(NSString *)privateKey { } 

看起来像?

iOS有一个C API来做到这一点。 我从来没有用过它,但它看起来像你需要一个PKCS12格式的文件与私钥在其中,你用SecKeyPKCS12Imort导入并获得私钥。 然后该函数是SecKeyRawSign来签署你的string。

应该首先使用已知的字符编码将string转换为NSData对象 – 可能是UTF-8,并对NSData中的字节进行签名。

如果在string中使用非ASCII字符,并且确保使用定义良好的编码,则还需要注意如何表示某些字符。 例如,é可以表示为一个单一的Unicode号码,或者可以表示为Unicode紧急重音后跟字母e。

http://en.wikipedia.org/wiki/Precomposed_character

我已经尝试了数百万的签名方法,包括Keychain,提取SecKeyRef,证书(.p12),.pem密钥文件,但仍然没有达到我的主要目标:

  • 使用PKCS#1 v1.5和SHA1签名string摘要
  • 使用从服务器(JSON)接收的stringbase64密钥而不是使用证书文件。

我的私钥是一个PKCS#1私钥,格式如下:

 -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCx9YWznzT3irAArr+INM5m0i6UCNICq4E8yrWwPbGh8/kdU/oh ..... ..... ..... ..... ..... ..... ..... ..... eF9lWooBNGgSh5vmkgECQGJwmDLKohSKEtVwGOIp3S3j+CHs0vVnznmtmC9sfrj4 ef48Sx1KFI8iQa3Nfv5bokaJkiIVVx/eMaa96Vracjc= -----END RSA PRIVATE KEY----- 

最终我转移到了OpenSSL,事情变得更加明亮。 所以整个过程如下所示:

  1. 下载并构buildiOS OpenSSL库 。
  2. 将该lib添加到项目中。
  3. 使用OpenSSL来最终签署消息。

第1步:OpenSSL库

https://github.com/x2on/OpenSSL-for-iPhone下载库

将build-libssl.sh复制到您的项目文件夹中使用terminal运行以下命令:

 cd [your project folder] /build-libssl.sh 

第2步:添加OpenSSL

将OpenSSL中的“include”文件夹复制到您的项目文件夹中

将libcrypto * .a和libss * .a文件拖放到您的XCode文件夹中

打开你的“目标”的生成设置

Library Search Paths更改为$(inherited) “$(SRCROOT)”

更改要include User Header Search Paths

激活Always Search User Paths

第3步:签名

 #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; } 

如果您想使用SHA256或任何其他SHA,则必须更改以下内容:

 SHA_DIGEST_LENGTH => SHA256_DIGEST_LENGTH sign[128] => sign[256] SHA1(data, dataLen, hash) => SHA256(data, dataLen, hash) NID_sha1 => NID_sha256 

备选步骤3:签名(Swift)

由于Swift语言不是C ++的超集,因此不能直接与C ++结合,因此需要创buildC ++代码的Objective-C包装,然后从Swift代码中调用它(Obj-C)。

步骤3.1

为您的C ++代码创build一个Obj-C类。 重要提示:该文件必须使用.mm扩展名或设置types为Objective-C++ Source

OpenSSLWrapper.h

 #import <Foundation/Foundation.h> @interface OpenSSLWrapper : NSObject + (NSString*) signHeader:(NSString*) pTextString withPrivateKey: (NSString*) pPrivateKey; @end 

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 

步骤3.2

创build一个桥接头文件。

YourProject桥接,Header.h

 #import "OpenSSLWrapper.h" 

步骤3.3

在你的Swift文件中使用Obj-C的方法。

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) ; } 

在结果中,你有一个hex的NSString *签名摘要。

希望有所帮助