2015-04-07 18 views

risposta

4

C'è una libreria per la gestione delle coppie di chiavi pubbliche-private in Swift che ho creato di recente chiamata Heimdall, che consente di esportare facilmente la stringa Base64 formattata X.509 della chiave pubblica.

Per rispettare SO regole, io includo anche l'attuazione di questa risposta (in modo che si spiega da sé)

public func X509PublicKey() -> NSString? { 
    // Fetch the key, so that key = NSData of the public key 
    let result = NSMutableData() 

    let encodingLength: Int = { 
     if key.length + 1 < 128 { 
      return 1 
     } else { 
      return ((key.length + 1)/256) + 2 
     } 
    }() 

    let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 
     0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00] 

    var builder: [CUnsignedChar] = [] 

    // ASN.1 SEQUENCE 
    builder.append(0x30) 

    // Overall size, made of OID + bitstring encoding + actual key 
    let size = OID.count + 2 + encodingLength + key.length 
    let encodedSize = encodeLength(size) 
    builder.extend(encodedSize) 
    result.appendBytes(builder, length: builder.count) 
    result.appendBytes(OID, length: OID.count) 
    builder.removeAll(keepCapacity: false) 

    builder.append(0x03) 
    builder.extend(encodeLength(key.length + 1)) 
    builder.append(0x00) 
    result.appendBytes(builder, length: builder.count) 

    // Actual key bytes 
    result.appendData(key) 

    // Convert to Base64 and make safe for URLs 
    var string = result.base64EncodedStringWithOptions(.allZeros) 
    string = string.stringByReplacingOccurrencesOfString("/", withString: "_") 
    string = string.stringByReplacingOccurrencesOfString("+", withString: "-") 

    return string 
} 

public func encodeLength(length: Int) -> [CUnsignedChar] { 
    if length < 128 { 
     return [CUnsignedChar(length)]; 
    } 

    var i = (length/256) + 1 
    var len = length 
    var result: [CUnsignedChar] = [CUnsignedChar(i + 0x80)] 

    for (var j = 0; j < i; j++) { 
     result.insert(CUnsignedChar(len & 0xFF), atIndex: 1) 
     len = len >> 8 
    } 

    return result 
} 

ho rimosso i dati di recupero di codice, fare riferimento a entrambe le fonti di Heimdall o Jeff Hay's answer

4

Se la chiave pubblica è già nel portachiavi, è possibile cercare la chiave pubblica e restituire i dati in Base64 con qualcosa di simile al seguente:

// Create dictionary to specify attributes for the key we're 
// searching for. Swift will automatically bridge native values 
// to to right types for the SecItemCopyMatching() call. 
var queryAttrs = [NSString:AnyObject]() 
queryAttrs[kSecClass] = kSecClassKey 
queryAttrs[kSecAttrApplicationTag] = publicKeyTag 
queryAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA 
queryAttrs[kSecReturnData] = true 

var publicKeyBits = Unmanaged<AnyObject>?() 
SecItemCopyMatching(queryAttrs, &publicKeyBits) 

// Work around a compiler bug with Unmanaged<AnyObject> types 
// the following two lines should simply be 
// let publicKeyData : NSData = publicKeyRef!.takeRetainedValue() as NSData 
let opaqueBits = publicKeyBits?.toOpaque() 
let publicKeyData = Unmanaged<NSData>.fromOpaque(opaqueBits).takeUnretainedValue() 

let publicKeyBase64 = publicKeyData.base64EncodedData(NSDataBase64EncodingOptions.Encoding64CharacterLineLength) 

Se è necessario generare la coppia di chiavi e conservare nel portachiavi, utilizzare qualcosa in questo senso:

// Create dictionaries to specify key attributes. Swift will 
// automatically bridge native values to to right types for the 
// SecKeyGeneratePair() call. 
var pairAttrs = [NSString:AnyObject]() 
var privateAttrs = [NSString:AnyObject]() 
var publicAttrs = [NSString:AnyObject]() 

privateAttrs[kSecAttrIsPermanent] = true 
privateAttrs[kSecAttrApplicationTag] = privateKeyTag 

publicAttrs[kSecAttrIsPermanent] = true 
publicAttrs[kSecAttrApplicationTag] = publicKeyTag 

pairAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA 
pairAttrs[kSecAttrKeySizeInBits] = 2048 
pairAttrs[(kSecPrivateKeyAttrs.takeUnretainedValue() as! String)] = privateAttrs 
pairAttrs[(kSecPublicKeyAttrs.takeUnretainedValue() as! String)] = publicAttrs 

var publicKeyPtr = Unmanaged<SecKey>?() 
var privateKeyPtr = Unmanaged<SecKey>?() 

let status = SecKeyGeneratePair(pairAttrs, &publicKeyPtr, &privateKeyPtr) 

Nota:publicKeyTag e privateKeyTag sono stringhe utilizzate per identificare la chiave nel keystore. Apple consiglia la notazione reverse-dns (com.company.key.xxx), ma finché sono unici, tutto dovrebbe essere buono.

Problemi correlati