Retrieve SecKey from RSA private key string encoded with passphrase in Swift or Objective C

旧街凉风 提交于 2020-05-13 13:25:10

问题


We have an enterprise mobile app that ships with an encrypted private key. We intend to provide users with the passphrase in order to use that private key, which will then allow them to communicate with a backend server. I've previously set this up using Python or C# but cannot figure out how to do this in Swift or Objective C. I've adapted some of this from this stack overflow question: Encrypt using RSA Certificate in Swift

     static func getCertificate(from certificate: String?, usingPhrase phrase: String?) -> SecKey? {
        guard let certificate = certificate else {
            print("Nil string passed in, nil being returned")
            return nil
        }
        let beginning = "-----BEGIN ENCRYPTED PRIVATE KEY-----"
        let tail = "-----END ENCRYPTED PRIVATE KEY-----"
        let certificateString = certificate.replacingOccurrences(of: beginning, with: "")
                                           .replacingOccurrences(of: tail, with: "")
                                           .replacingOccurrences(of: "\n", with: "")
                                           .replacingOccurrences(of: " ", with: "")
        guard let data = Data(base64Encoded: certificateString) else {
            print("Unable to cast string to data")
            return nil
        }

        // ** I'm assuming here is where I need to decrypt the key before I can create the certificate **

        guard let cert = SecCertificateCreateWithData(nil, data as NSData) else {
            print("Unable to cast certificate to SecCertificate")
            return nil
        }

        var secTrust: SecTrust?

        // Retrieve a SecTrust using the SecCertificate object. Provide X509 as policy
        let status = SecTrustCreateWithCertificates(cert, SecPolicyCreateBasicX509(), &secTrust)

        // Check if the trust generation is success
        guard status == errSecSuccess else { return nil }

        // Retrieve the SecKey using the trust hence generated
        guard let trust = secTrust else {
            print("Trust policy not created")
            return nil
        }

        // ** I acknowledge that this method creates a public key and I am passing in a private key
        // ** I am not sure what method needs to be used instead
        guard let secKey = SecTrustCopyPublicKey(trust) else { return nil }

        return secKey
    }

Ultimately, I need to decrypt the private key using a passphrase. I was planning on using it as a SecKey, but getting the Base64 String representation of it works for me as well. I am comfortable working through an Objective-C or Swift based answer.

EDIT Here is a sample key for test purposes:

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIj6w/NvIjTXICAggA
MBQGCCqGSIb3DQMHBAi6qjkA0+yxyQSCBMhqdUDLRCLUjbgqe3rbF2lHn6yTsYbk
pfLWHkKT4pvQtaqXJvPZErb3E27va3HXvVDJfJS0/iwsnzIn6p2J9ZtgIGs4OBRU
kUw8lVAhNHTkAw/sj+OHdWexfOL5vKE3DgXqnAVGyhm4CNDXQ/9UDqkmtmHsMOlz
nqbOdWhMS/Uj/Dh41urw3sstpX4wZCHGTFNDL83pDAv7jfAZF/NSQq8ft/BPknMu
HLvYvd3fR4iKqKswcvR5c2q+CLbfEbXbVty6B/JMDSoi3wuh9lezMesIhTUYDSaK
QgkCEtrJ4FsO/tPXtyGvCjKVgvfvn8njQPtphq/gbKBeXpopsFGi19iY8fCkPQSb
Cp6FttMvJPwJvIb/qUZWGu9OWaBhmn0MH+qtXED6yxqXSyQDRYg1Vurfm0azQxUb
zJIy8qgla9GVvoGYpIGDvsQZFzur6le8G6/6c85raI9LZ88Bo8gEsTeQgPMxG1c+
7kRvn/hl/n0Oh8VsPOHjx2N/Y9vcmlyIlCDPIuGiYcNy1ICDv/kaBD9JVJVA5S7X
+MRZG8+EesjTiZseVUwK9OhnE4Jws2UzAk3zfMvzvnAgxue/FcRPUfYiHakNu83z
SFqayIUGz3zD0XLdWBVrh2QPvxW6eP3AFdIpjrPzwq1kDDw19VaAu7mw7JexrOyW
qvCO/VIHXqflL/OCxPT5BUQ9pbxTCEfv5wbWzczKWWub0AhPexDBW7wat3HwUGeb
oeEwnmNxAXxxz/RJeK1zKUAKGWQPI8X4bG/IZFmk1dgeJ8bo9My5b05Zw9d/gw7C
Xi5nZ5sG5ERp3jKLsT2czbr66w4HV4L38mASVtTUeXyySvnz//Ib40FC46Gi7SqP
pcpl1CrDi0UWe/cbQ/qkcaFrgdvIGsuSfZf8amq1FHnB47NUblYmm1WPCqeNtgzY
srAy/aVtF6FvG+uy6sCrP76c9HY1ZvyeO/82t/Sd5jnoq+VCKtarRNjEEfdwNGQp
X/ycspdn+a0XkXthSBvHWcCmQmgAV8Yp5TR0r2PgGqHk3lRq9/yKWy1gRuPSiRpZ
HzOOfZ4DmVELRf5R5+UCVJ5idkKZb2t+R7rl5/9grf8iCeUPngIkxrZvr4b7/mQm
fkmIMSUYT9CVeBprF5f2wLbbAmPpoUnULTnVzrOhZYCZGRQLyGGdX+CELBNxc8Er
dt4deeutCQm+H0d5V09HO9AOAwlESyt9q4CEAcSzSzzMygvWLe04csdcCSV2htAm
n0zDwhqGZ2LI+dUTGw4apOdBuNeveaHBrlp7XhCIOJ35SAWrb8baPizwl4iw5fA0
ucBZzRDAavDhj6XMQSwsOaCfzYfpASqwkm2Zjk3znWS18xpXRxvgqfCHpJRo9M4f
SQlRpT3Nqw5vn8BV+ioBvwxQd/1XsMbjKKwbwk+1wB/E/mHAiIQUQJ6Ec/WqzKqn
biqlBuSGLrS5O8ynu83DERFiatCAkNkl6nCaWtNu2KWtKM52y03BN3MBxS1kU+FI
afb7mN75j1gTZFH6EmujfVfrL/f8aO1dkxHO4IuWb5r7DaY7AByZgo1EKGiSIh3N
rtQVsAQr1/NcO6GVSHQU5egpI/eocvHvrAzsvlE2sqNBKm4NVogXjms7avKIbtA4
+Ro=
-----END ENCRYPTED PRIVATE KEY-----

The passcode for this key is

8720c10d735d7fb218b9e48db942a494

回答1:


I took the sample encrypted key you provided and pasted it into this excellent ASN.1 decoder. It produces the following result:

Which is actually a very useful summary of the steps required to decrypt the ciphertext using the key you have:

  • The first two OBJECT IDENTIFIER entries hint at the padding mode used during encryption and the key derivation function used to obtain an encryption key from your "passcode": PKCS #5 padding and PBKDF2 for key derivation. The OCTET STRING and INTEGER values under that are the salt and iteration count for PBKDF2.
  • The third OBJECT IDENTIFIER indicates the encryption algorithm - TripleDES in CBC mode. Not ideal, but secure enough I guess. The OCTET STRING under that is the 8-byte IV, since DES has an 64 bit block size.
  • The final OCTET STRING is the ciphertext.

So, in summary, you need to:

  • Find a way to get at the values you need e.g. salt, iteration count, IV and ciphertext - assuming the algorithms used for these keys stay the same. Sometimes you can get away with jumping around in the raw data and slicing these values out - depending on your needs, you might need to use an ASN.1 decoder.
  • When it comes time to decrypt - pull out the salt and iteration count (first OCTET STRING and INTEGER). Pull out the IV (second OCTET STRING) and the ciphertext (last OCTET STRING).
  • Apply PBKDF2 using the specified salt and iteration count to your passcode, the one you provide in the question. You'll need to extract 192 bits of key material from this, since we're using TripleDES.
  • Decrypt the ciphertext using the key material from the last step in CBC mode using the IV you extracted. Use PCKS#5 padding, which is usually the default.
  • Done!


来源:https://stackoverflow.com/questions/61428695/retrieve-seckey-from-rsa-private-key-string-encoded-with-passphrase-in-swift-or

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!