2015-04-07 125 views

回答

4

我最近创建的Swift中有一个用于处理公私密钥对的库,名为Heimdall,它允许您轻松导出公钥的X.509格式的Base64字符串。

为了符合SO规则,我也将包括在该答案的执行(使得它是不言自明)

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 
} 

我已经删除了数据取代码,指的Heimdall源或Jeff Hay's answer

4

如果公钥已在您的钥匙串,你可以看一下公钥和为base64类似下面的东西返回数据:

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

如果你需要生成密钥对和商店它在钥匙串,使用这些方针的东西:

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

注:publicKeyTagprivateKeyTag是用于标识密钥库的钥匙串。 Apple建议使用反向DNS表示法(com.company.key.xxx),但只要它们是唯一的,一切都应该是好的。

相关问题