Tag: rsa

[教學] iOS 上使用 RSA Public Key 加密

使用 openssl 產生 key

private key

openssl genrsa -out private_key.pem 1024

pkcs8 private key

這是程式會用到的 private key

openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt

pkcs8_private_key.pem 內容

-----BEGIN RSA PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJavPhrQDMVIVq5wv5WDFGxeWcQk
XW+fsL/z6hui9WRNztAw+NENAuC/tciF9MibGI/sFcRunriGVyKFsIy7QFknKf4zz3E2uE+GPfeV
RyP3SsWN/cj/OU7QaT6mhpa007Niyy40Uy2PqCCbUQlgHCLr65gLwTz9fLjj7noHjRvFAgMBAAEC
gYAuBEplCdA8l0DReOEpGaStC4tCWRCnvA7QL/74faWPAiv8bFgwD1cnp6QuHqqIcMTpfuGO4XFb
TLtjcYxfDfgyR1N6JbnG06oL1MlTmwfZjIrwGfhDurR0cvlNDzTlMyGfHux+0L6Wgujz4WVvC1l8
cIS/L9LkKM6jri336N2AwQJBAPCBe3Izu4izP7iqYq3FjWtW6WJY2BgG1vefnXFN99SRoEVuQLuM
mC3Ol8Tfvt4+mRuFIPA1PgKtrScNbCZlOy0CQQCgZGRzoo8BvSGfg4/v080vXWDAOGz2v6qidFau
RrYNlD26PL+p+kthMQPiEMotcAy3ssfJRhsftqjt5h5K5OH5AkEArQAW8lEwJub5gTZfASzHy1yb
SLkryCyzWTAhqq0xBmEybn8eZUp+9QRUu7NOssNIkzkyNle2IWsY0KyhDQVoiQJBAJUhIwEdSUg9
mTCee8tqrCH4+YdgL3gxd6866ol597Wies5Zw3+A2GuSzmB4afNbdoeqs/XhuECBbopb5xiNvckC
QQCNyF165oFTkWwi7MvD+y8rsatzzVmwiJDOYEpNDSUB7a3pjppairwi8CgDHbDOuoKlDPPYr7rW
LHsJq+0suREU
-----END RSA PRIVATE KEY-----

public key

openssl rsa -in private_key.pem -out public_key.pem -pubout

public_key.pem 內容

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWrz4a0AzFSFaucL+VgxRsXlnEJF1vn7C/8+ob
ovVkTc7QMPjRDQLgv7XIhfTImxiP7BXEbp64hlcihbCMu0BZJyn+M89xNrhPhj33lUcj90rFjf3I
/zlO0Gk+poaWtNOzYssuNFMtj6ggm1EJYBwi6+uYC8E8/Xy44+56B40bxQIDAQAB
-----END PUBLIC KEY-----

加密方式

在 iOS 上有兩種方式可以做到 RSA 加解密的功能

  1. 使用 iOS 內建 Security.framework
  2. 使用 SSCrypto.framework + openssl

Security.framework

設定 public Key

- (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
    // Skip ASN.1 public key header
    if (d_key == nil) return(nil);
 
    unsigned int len = [d_key length];
    if (!len) return(nil);
 
    unsigned char *c_key = (unsigned char *)[d_key bytes];
    unsigned int  idx    = 0;
 
    if (c_key[idx++] != 0x30) return(nil);
 
    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;
 
    // PKCS #1 rsaEncryption szOID_RSA_RSA
    static unsigned char seqiod[] =
    { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
     0x01, 0x05, 0x00 };
    if (memcmp(&c_key[idx], seqiod, 15)) return(nil);
 
    idx += 15;
 
    if (c_key[idx++] != 0x03) return(nil);
 
    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;
 
    if (c_key[idx++] != '\0') return(nil);
 
    // Now make a new NSData from this buffer
    return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}
- (BOOL)addPublicKey:(NSString *)key withTag:(NSString *)tag
{
    NSString *s_key = [NSString string];
    NSArray  *a_key = [key componentsSeparatedByString:@"\n"];
    BOOL     f_key  = FALSE;
 
    for (NSString *a_line in a_key) {
        if ([a_line isEqualToString:@"-----BEGIN PUBLIC KEY-----"]) {
            f_key = TRUE;
        }
        else if ([a_line isEqualToString:@"-----END PUBLIC KEY-----"]) {
            f_key = FALSE;
        }
        else if (f_key) {
            s_key = [s_key stringByAppendingString:a_line];
        }
    }
    if (s_key.length == 0) return(FALSE);
 
    // This will be base64 encoded, decode it.
    NSData *d_key = [NSData dataFromBase64String:s_key];
    d_key = [self stripPublicKeyHeader:d_key];
    if (d_key == nil) return(FALSE);
 
    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
 
    // Delete any old lingering key with the same tag
    NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
    [publicKey setObject:(id) kSecClassKey forKey:(id)kSecClass];
    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [publicKey setObject:d_tag forKey:(id)kSecAttrApplicationTag];
    SecItemDelete((CFDictionaryRef)publicKey);
 
    CFTypeRef persistKey = nil;
 
    // Add persistent version of the key to system keychain
    [publicKey setObject:d_key forKey:(id)kSecValueData];
    [publicKey setObject:(id) kSecAttrKeyClassPublic forKey:(id)
     kSecAttrKeyClass];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)
     kSecReturnPersistentRef];
 
    OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey, &persistKey);
    if (persistKey != nil) CFRelease(persistKey);
 
    if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) {
        [publicKey release];
        return(FALSE);
    }
 
    // Now fetch the SecKeyRef version of the key
    SecKeyRef keyRef = nil;
 
    [publicKey removeObjectForKey:(id)kSecValueData];
    [publicKey removeObjectForKey:(id)kSecReturnPersistentRef];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef
    ];
    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    secStatus = SecItemCopyMatching((CFDictionaryRef)publicKey,
                                    (CFTypeRef *)&_publicKeyRef);
 
    [publicKey release];
 
    if (_publicKeyRef == nil) return(FALSE);
    return(TRUE);
}

這兩段 stripPublicKeyHeader, addPublicKey 來自 Using an RSA public key generated by OpenSSL in iOS

加密

- (NSData*)encrypt:(NSString*)text {
    OSStatus sanityCheck = noErr;
    size_t cipherBufferSize = 0;
    size_t keyBufferSize = 0;
 
    NSData * data = [text dataUsingEncoding:NSUTF8StringEncoding];    
    NSData * cipher = nil;
    uint8_t * cipherBuffer = NULL;
 
    // Calculate the buffer sizes.
    cipherBufferSize = SecKeyGetBlockSize(_publicKeyRef);
    keyBufferSize = [data length];
 
    // Allocate some buffer space. I don't trust calloc.
    cipherBuffer = malloc( cipherBufferSize * sizeof(uint8_t) );
    memset((void *)cipherBuffer, 0x0, cipherBufferSize);
 
    // Encrypt using the public key.
    sanityCheck = SecKeyEncrypt(_publicKeyRef,
                                kSecPaddingPKCS1,
                                (const uint8_t *)[data bytes],
                                keyBufferSize,
                                cipherBuffer,
                                &cipherBufferSize
                                );
 
    // Build up cipher text blob.
    cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
 
    if (cipherBuffer) free(cipherBuffer);
 
    return cipher;
}

SSCrypto.framework + openssl [推薦]

使用 openssl 就相對簡單許多

加密

static NSString *publicKey =
@"-----BEGIN PUBLIC KEY-----\n\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdsg9OlT8nJys9U/ZahRXjgy/0\n\
/KrFpdXdu1I8CLmAb8iONKgtbOhkob/BibZR21dIM9gcuc7NIH9zqptflXmZ9hfJ\n\
f0DivZ9ganPITBSkuM3wni67rT2sBY5bOvrUC7v77RZJYmiUlOCpEWrOJhfN23Vx\n\
wJ4MhnGHHYzUadLF3wIDAQAB\n\
-----END PUBLIC KEY-----";
- (NSData*)encrypt:(NSString*)text {
    //Convert to NSData
    NSData *key1 = [_publicKey dataUsingEncoding:NSASCIIStringEncoding];
 
    SSCrypto *rsa = [[SSCrypto alloc] initWithPublicKey:key1];
    [rsa setClearTextWithString:text];
    NSData *dataEncrypt = [rsa encrypt];
    return dataEncrypt;
}
Tags : , , ,