我可以从 Swift 中的 SecKeyRef 对象中获取模数或指数吗? [英] Can I get the modulus or exponent from a SecKeyRef object in Swift?

查看:28
本文介绍了我可以从 Swift 中的 SecKeyRef 对象中获取模数或指数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Swift 中,我创建了一个 SecKeyRef 对象,通过调用 SecTrustCopyPublicKey 在一些原始 X509 证书数据上.这就是 SecKeyRef 对象的样子.

In Swift, I created a SecKeyRef object by calling SecTrustCopyPublicKey on some raw X509 certificate data. This is what this SecKeyRef object looks like.

Optional(<SecKeyRef algorithm id: 1,
key type: RSAPublicKey,
version: 3, block size: 2048 bits,
exponent: {hex: 10001, decimal: 65537},
modulus: <omitted a bunch of hex data>,
addr: 0xsomeaddresshere>)

基本上,这个 SecKeyRef 对象包含一大堆信息关于公钥,但似乎没有办法真正转换这个 SecKeyRef 转换成字符串、NSData 或其他任何内容(这是我的目标,只是获取 base64 公钥).

Basically, this SecKeyRef object holds a whole bunch of information about the public key, but there seems to be no way to actually convert this SecKeyRef into a string, NSData, or anything else (this is my goal, is just to get a base64 public key).

但是,我有一个函数,我可以给出一个 modulus 和一个 exponent,它只会计算公钥是什么.我已经通过传入从上述 SecKeyRef 记录的数据对其进行了测试.

However, I have a function that I can give a modulus and an exponent, and it will just calculate what the public key is. I've tested it by passing in the data that's logged from the above SecKeyRef.

但不知何故,我无法从 SecKeyRef 对象访问这些属性(我只能在控制台中看到整个对象;例如,我不能执行 SecKeyRef.modulus 或类似的东西,似乎).

But somehow I can't access those properties from the SecKeyRef object (I can only see the whole object in the console; for example, I cannot do SecKeyRef.modulus or anything of the sort, it seems).

我的问题:如何访问 SecKeyRef.modulus,或者将这个 SecKeyRef 转换为 NSData 或类似的东西?谢谢

My question: how can I access SecKeyRef.modulus, or alternatively, convert this SecKeyRef into NSData or something similar? Thanks

(更多信息)

我正在通过这个函数动态创建我的 SecKeyRef:

I am creating my SecKeyRef dynamically, through this function I have:

func bytesToPublicKey(certData: NSData) -> SecKeyRef? {
    guard let certRef = SecCertificateCreateWithData(nil, certData) else { return nil }
    var secTrust: SecTrustRef?
    let secTrustStatus = SecTrustCreateWithCertificates(certRef, nil, &secTrust)
    if secTrustStatus != errSecSuccess { return nil }
    var resultType: SecTrustResultType = UInt32(0) // result will be ignored.
    let evaluateStatus = SecTrustEvaluate(secTrust!, &resultType)
    if evaluateStatus != errSecSuccess { return nil }
    let publicKeyRef = SecTrustCopyPublicKey(secTrust!)

    return publicKeyRef
}

这样做是从证书中获取原始字节流(例如,可以从使用 PKI 的硬件广播),然后将其转换为 SecKeyRef.

What that does is takes the raw byte stream from a certificate (which can be broadcasted from, say, a piece of hardware using PKI), and then turns that into a SecKeyRef.

(截至 2015 年 1 月 7 日对现有答案的评论)

(comments on existing answers as of 7 January 2015)

这不起作用:

let mirror = Mirror(reflecting: mySecKeyObject)

for case let (label?, value) in mirror.children {
    print (label, value)
}

这会在控制台中产生以下输出:

This results in this output in the console:

Some <Raw SecKeyRef object>

不确定字符串Some"是什么意思.

Not sure what the string "Some" means.

此外,mirror.descendant("exponent")(或modulus")会导致 nil,即使在控制台中打印原始对象时,我也可以清楚地看到这些属性存在,并且它们实际上是填充的.

Additionally, mirror.descendant("exponent") (or "modulus") results in nil, even though when printing the raw object in the console, I can clearly see that those properties exist, and that they are in fact populated.

另外,如果可能的话,我希望避免保存到钥匙串,读取为 NSData,然后从钥匙串中删除.如赏金描述中所述,如果这是唯一可能的方法,请引用权威参考.感谢您迄今为止提供的所有答案.

Also, if at all possible, I would like to avoid having to save to the keychain, reading as NSData, and then deleting from the keychain. As stated in the bounty description, if this is the only way possible, please cite an authoritative reference. Thank you for all answers provided so far.

推荐答案

确实可以不使用钥匙串也不私有API来提取模数和指数.

It is indeed possible to extract modulus and exponent using neither keychains nor private API.

有(公开但未记录)函数SecKeyCopyAttributesSecKey 中提取 CFDictionary.属性键的一个有用来源是 SecItemConstants.c

There is the (public but undocumented) function SecKeyCopyAttributes which extracts a CFDictionary from a SecKey. A useful source for attribute keys is SecItemConstants.c

检查这本字典的内容,我们发现一个条目 "v_Data" : <binary>.它的内容是 DER 编码的 ASN

Inspecting the content of this dictionary, we find an entry "v_Data" : <binary>. Its content is DER-encoded ASN for

SEQUENCE {
    modulus           INTEGER, 
    publicExponent    INTEGER
}

请注意,如果整数是正数且具有前导 1 位,则用零字节填充(以免将它们与二补负数混淆),因此您可能会发现比预期多一个字节.如果发生这种情况,就把它剪掉.

Be aware that integers are padded with a zero byte if they are positive and have a leading 1-bit (so as not to confuse them with a two-complement negative number), so you may find one byte more than you expect. If that happens, just cut it away.

您可以为这种格式实现解析器,或者在知道您的密钥大小的情况下对提取进行硬编码.对于 2048 位密钥(和 3 字节指数),格式为:

You can implement a parser for this format or, knowing your key size, hard-code the extraction. For 2048 bit keys (and 3-byte exponent), the format turns out to be:

30|82010(a|0)        # Sequence of length 0x010(a|0)
    02|82010(1|0)    # Integer  of length 0x010(1|0)
        (00)?<modulus>
    02|03            # Integer  of length 0x03
        <exponent>

总共是 10 + 1?+ 256 + 3 = 269 或 270 字节.

For a total of 10 + 1? + 256 + 3 = 269 or 270 bytes.

import Foundation
extension String: Error {}

func parsePublicSecKey(publicKey: SecKey) -> (mod: Data, exp: Data) {
    let pubAttributes = SecKeyCopyAttributes(publicKey) as! [String: Any]

    // Check that this is really an RSA key
    guard    Int(pubAttributes[kSecAttrKeyType as String] as! String)
          == Int(kSecAttrKeyTypeRSA as String) else {
        throw "Tried to parse non-RSA key as RSA key"
    }

    // Check that this is really a public key
    guard    Int(pubAttributes[kSecAttrKeyClass as String] as! String) 
          == Int(kSecAttrKeyClassPublic as String) 
    else {
        throw "Tried to parse non-public key as public key"
    }

    let keySize = pubAttributes[kSecAttrKeySizeInBits as String] as! Int

    // Extract values
    let pubData  = pubAttributes[kSecValueData as String] as! Data
    var modulus  = pubData.subdata(in: 8..<(pubData.count - 5))
    let exponent = pubData.subdata(in: (pubData.count - 3)..<pubData.count) 

    if modulus.count > keySize / 8 { // --> 257 bytes
        modulus.removeFirst(1)
    }

    return (mod: modulus, exp: exponent)
}

(我最终写了一个完整的 ASN 解析器,所以这段代码没有经过测试,小心!)

(I ended up writing a full ASN parser, so this code is not tested, beware!)

请注意,您可以以非常相似的方式提取 private 密钥的详细信息.使用 DER 术语,这是 v_Data 的格式:

Note that you can extract details of private keys in very much the same way. Using DER terminology, this is the format of v_Data:

PrivateKey ::= SEQUENCE {
    version           INTEGER,
    modulus           INTEGER,  -- n
    publicExponent    INTEGER,  -- e
    privateExponent   INTEGER,  -- d
    prime1            INTEGER,  -- p
    prime2            INTEGER,  -- q
    exponent1         INTEGER,  -- d mod (p-1) (dmp1)
    exponent2         INTEGER,  -- d mod (q-1) (dmq1)
    coefficient       INTEGER,  -- (inverse of q) mod p (coeff)
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
 }

手动解析它可能是不明智的,因为任何整数都可能已被填充.

Parsing this by hand is probably ill-advised since any of the integers may have been padded.

注意事项:如果密钥是在macOS上生成的,则公钥的格式会有所不同;上面给出的结构是这样包装的:

Nota bene: The format of the public key is different if the key has been generated on macOS; the structure given above is wrapped like so:

SEQUENCE {
    id              OBJECTID,
    PublicKey       BITSTRING
}

位串是上述形式的 DER 编码的 ASN.

The bit-string is DER-encoded ASN of the form above.

这篇关于我可以从 Swift 中的 SecKeyRef 对象中获取模数或指数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆