簡體   English   中英

使用rsa私鑰對數據簽名

[英]sign data using rsa private key

我知道是聖誕節,但是我有一個很大的問題需要解決,我在這里尋找我的聖誕節奇跡...

我已經閱讀了Apple文檔,並且僅提供有關如何從證書創建RSA公鑰和私鑰的指南。 就我而言,.pem文件中只有RSA私鑰。 所以我的問題是他:我應該如何使用該密鑰對數據簽名? 我不想使用openssl 我沒有運氣就嘗試過,而且我認為可以通過使用apples API與RSA簽署數據。

這是我的密鑰的樣子:

-----BEGIN RSA PRIVATE KEY-----
..............................
-----END RSA PRIVATE KEY-----

這是我到目前為止所做的:

-(NSString *)signing:(NSString *)dataString {
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"PrestaMobilekey" ofType:@"pem"];
    NSData *data = [[NSData alloc]initWithContentsOfFile:filePath];

    SecKeyRef privateKey = (__bridge SecKeyRef)(data);

    uint8_t *signedHashBytes = NULL;
    // calculate private key size
    size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey);

    // create space to put signature
    signedHashBytes = (uint8_t *)malloc(signedHashBytesSize * sizeof(uint8_t));
    memset((void *)signedHashBytes, 0x0, signedHashBytesSize);

    OSStatus status = NULL;

    // sign data
    status = SecKeyRawSign(privateKey,
                           kSecPaddingPKCS1SHA1,
                           [[[dataString dataUsingEncoding:NSUTF8StringEncoding] SHA1] bytes],
                           CC_SHA1_DIGEST_LENGTH,
                           signedHashBytes,
                           &signedHashBytesSize);

    if (privateKey) {
        CFRelease(privateKey);
    }

    // get signature hash
    NSData *signedHash = [NSData dataWithBytes:(const void *)signedHashBytes length:(NSUInteger)signedHashBytesSize];

    // release created space
    if (signedHashBytes) {
        free(signedHashBytes);
    }

    if (status != errSecSuccess) {
        return @"";
    }

    // return Base64 encoded signature string
    return [Base64 encode:signedHash];
}

我真的希望有人能提供一些好的信息和答案來幫助我。

謝謝。

您不需要使用OpenSSL。 您可以通過一些調整使用方法對數據進行簽名。 我認為您不能簡單地將NSData對象橋接並轉換為SecKeyRef 您最有可能需要先將其保存到鑰匙串中。

您可以使用以下方法進行操作:

- (SecKeyRef)saveKeyToKeychain:(NSData *)key keySize:(NSUInteger)keySize private:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;
    if (isPrivate) {
            tag = privateTag;
            keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
            tag = publicTag;
            keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *saveDict = @{
                    (__bridge id) kSecClass : (__bridge id) kSecClassKey,
                    (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
                    (__bridge id) kSecAttrApplicationTag : tag,
                    (__bridge id) kSecAttrKeyClass : keyClass,
                    (__bridge id) kSecValueData : key,
                    (__bridge id) kSecAttrKeySizeInBits : [NSNumber numberWithUnsignedInteger:keySize],
                    (__bridge id) kSecAttrEffectiveKeySize : [NSNumber numberWithUnsignedInteger:keySize],
                    (__bridge id) kSecAttrCanDerive : (__bridge id) kCFBooleanFalse,
                    (__bridge id) kSecAttrCanEncrypt : (__bridge id) kCFBooleanTrue,
                    (__bridge id) kSecAttrCanDecrypt : (__bridge id) kCFBooleanFalse,
                    (__bridge id) kSecAttrCanVerify : (__bridge id) kCFBooleanTrue,
                    (__bridge id) kSecAttrCanSign : (__bridge id) kCFBooleanFalse,
                    (__bridge id) kSecAttrCanWrap : (__bridge id) kCFBooleanTrue,
                    (__bridge id) kSecAttrCanUnwrap : (__bridge id) kCFBooleanFalse
    };

    SecKeyRef savedKey = NULL;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) saveDict, (CFTypeRef *)&savedKey);
    if (sanityCheck != errSecSuccess) {
            LOGGING_FACILITY1(sanityCheck != noErr, @"Problem saving the key to keychain, OSStatus == %d.", sanityCheck);
    }

    return savedKey;
}

如果不想立即獲取引用,可以將方法類型更改為void並刪除return語句。 (CFTypeRef *)&savedKey更改為NULL

然后,您可以像這樣檢索保存的密鑰:

- (SecKeyRef)getKeyRef:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;
    if (isPrivate) {
        if (privateKeyRef != NULL) {
            // already exists in memory, return
            return privateKeyRef;
        }
        tag = privateTag;
        keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
        if (publicKeyRef != NULL) {
            // already exists in memory, return
            return publicKeyRef;
        }
        tag = publicTag;
        keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *queryDict = @{
            (__bridge id) kSecClass : (__bridge id) kSecClassKey,
            (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
            (__bridge id) kSecAttrApplicationTag : tag,
            (__bridge id) kSecAttrKeyClass : keyClass,
            (__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue
    };

    SecKeyRef keyReference = NULL;
    sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef) queryDict, (CFTypeRef *) &keyReference);
    if (sanityCheck != errSecSuccess) {
        NSLog(@"Error trying to retrieve key from server. isPrivate: %d. sanityCheck: %li", isPrivate, sanityCheck);
    }

    if (isPrivate) {
        privateKeyRef = keyReference;
    }
    else {
        publicKeyRef = keyReference;
    }
    return keyReference;
}

另外,返回base64編碼的字符串的一種更簡單的方法是執行以下操作:

NSString *signatureString = [signedHash base64EncodedStringWithOptions:nil];

關於privateTag和publicTag

privateTagpublicTag用於標記kSecAttrApplicationTag ,它定義了使用此密鑰的應用程序。 您希望有一個單獨的privateTagpublicTag來區分私鑰和公鑰。

這有點令人費解,因為我遵循了示例代碼,但是我通過以下方式定義了privateTagpublicTag

SecKeyWrapper.h

#define kPublicKeyTag           "com.sample.app.publickey"
#define kPrivateKeyTag          "com.sample.app.privatekey"

SecKeyWrapper.m

// just under @implementation or @synthesize lines
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
static const uint8_t privateKeyIdentifier[] = kPrivateKeyTag;

- (id)init {
    if (self = [super init]) {
        // Tag data to search for keys.
        privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
        publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    }

    return self;
}

然后像在我上面提供的代碼示例中那樣使用privateTagpublicTag

好吧,我自己找到了解決這個問題的辦法。 我希望這對其他人有幫助... 就是幫助我的原因。 我以為不用openssl就可以做到這一點,但是我錯了。 但是,仍然可以像在那篇文章中那樣,在項目中不需要額外的庫。 使用終端

暫無
暫無

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

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