簡體   English   中英

使用RSA私鑰對字符串簽名

[英]Sign a string with an RSA private key

在我的應用程序中,我必須使用已經擁有的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以對您的字符串進行簽名。

首先應使用已知的字符編碼將字符串轉換為NSData對象-可能為UTF-8,並對NSData中的字節進行簽名。

如果在字符串中使用非ASCII字符,並確保使用定義良好的編碼,則還需要注意某些字符的表示方式。 例如,é可以表示為單個Unicode數字,也可以表示為Unicode重音符號,后跟字母e。

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

我已經嘗試了數百萬種簽名方法,包括鑰匙串,提取SecKeyRef,證書(.p12)、. pem密鑰文件,但仍然無法實現我的主要目標:

  • 使用PKCS#1 v1.5和SHA1簽署字符串摘要
  • 使用從服務器(JSON)接收到的字符串base64密鑰,而不使用證書文件。

我的私鑰是一個格式如下的PKCS#1私鑰:

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

最終,我搬到了OpenSSL,事情變得更加光明。 因此,整個過程如下所示:

  1. 下載並構建iOS OpenSSL庫
  2. 將庫添加到項目。
  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)”

更改User Header Search Pathsinclude

激活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語言不是C ++的超集,因此不能直接與C ++組合,因此您需要創建一個C ++代碼的Objective-C包裝器,然后從您的Swift代碼中調用它(Obj-C)。

步驟3.1

為您的C ++代碼創建一個Obj-C類。 重要說明:該文件必須具有.mm擴展名或將類型設置為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

創建一個橋接頭文件。

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

}

結果,您得到一個十六進制的NSString *帶符號的摘要。

希望能有所幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM