这个部分研究用了我很多时间,终于找到一个方法.
一.核心:
IOS的key pair和java的是不通的,没办法直接转换,原因在于他们的DER(Distinguished Encoding Rules)是不一样的.IOS接收的是ASN.1格式,而java接收的是X509格式.
解决思路就是把ASN.1转换成X509,反之亦然.
(同样道理,private key的格式也是不通的,iOS 的是PKCS1,而java的是PKCS8)
二.转换:
具体流程就如上所示.
这里面需要用到另外一个库
参考:https://digitalleaves.com/blog/2015/10/sharing-public-keys-between-ios-and-the-rest-of-the-world/
"Exporting iOS-generated public keys to the outside world."这部分
这是GitHub:https://github.com/DigitalLeaves/CryptoExportImportManager
分析:
这个是export的总流程:
@IBAction func generateAndExportPublicKey(_ sender: AnyObject) { self.view.isUserInteractionEnabled = false self.textView.text = "Trying to get public key data from Keychain first..." let keyType = getKeyTypeFromSegmentedControl() if let publicKeyData = getPublicKeyData(kExportKeyTag + keyType) { self.textView.text = self.textView.text + "Success!\nPublic key raw bytes: \(publicKeyData.hexDescription)\n\n" self.exportKeyFromRawBytesAndShowInTextView(publicKeyData) self.view.isUserInteractionEnabled = true } else { self.textView.text = self.textView.text + "Failed! Will try to generate keypair...\n" createSecureKeyPair(kExportKeyTag + keyType) { (success, pubKeyData) -> Void in if success && pubKeyData != nil { self.textView.text = self.textView.text + "Success!\nPublic key raw bytes:\(pubKeyData!)\n" self.exportKeyFromRawBytesAndShowInTextView(pubKeyData!) } else { self.textView.text = self.textView.text + "Oups! I was unable to generate the keypair to test the export functionality." } self.view.isUserInteractionEnabled = true } } }
这里生成key pair:
func createSecureKeyPair(_ keyTag: String, completion: ((_ success: Bool, _ pubKeyData: Data?) -> Void)? = nil) { // private key parameters let privateKeyParams: [String: AnyObject] = [ kSecAttrIsPermanent as String: true as AnyObject, kSecAttrApplicationTag as String: keyTag as AnyObject, ] // private key parameters let publicKeyParams: [String: AnyObject] = [ kSecAttrApplicationTag as String: keyTag as AnyObject, kSecAttrIsPermanent as String: true as AnyObject ] // global parameters for our key generation let parameters: [String: AnyObject] = [ kSecAttrKeyType as String: getKeyTypeFromSegmentedControl() as AnyObject, kSecAttrKeySizeInBits as String: getKeyLengthFromSegmentedControl() as AnyObject, kSecPublicKeyAttrs as String: publicKeyParams as AnyObject, kSecPrivateKeyAttrs as String: privateKeyParams as AnyObject, ] // asynchronously generate the key pair and call the completion block DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { () -> Void in var pubKey, privKey: SecKey? let status = SecKeyGeneratePair(parameters as CFDictionary, &pubKey, &privKey) if status == errSecSuccess { DispatchQueue.main.async(execute: { print("Successfully generated keypair!\nPrivate key: \(privKey)\nPublic key: \(pubKey)") let publicKeyData = self.getPublicKeyData(kExportKeyTag + self.getKeyTypeFromSegmentedControl()) completion?(true, publicKeyData) }) } else { DispatchQueue.main.async(execute: { print("Error generating keypair: \(status)") completion?(false, nil) }) } } }
用的也是ios的api,可以参考Apple的文档:
https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys
/generating_new_cryptographic_keys
这样重新获取public key:(根据generate时的key tag)
func getPublicKeyData(_ keyTag: String) -> Data? { let parameters = [ kSecClass as String: kSecClassKey, kSecAttrKeyType as String: getKeyTypeFromSegmentedControl(), kSecAttrKeyClass as String: kSecAttrKeyClassPublic, kSecAttrApplicationTag as String: keyTag, kSecReturnData as String: true ] as [String : Any] var data: AnyObject? let status = SecItemCopyMatching(parameters as CFDictionary, &data) if status == errSecSuccess { return data as? Data } else { print("Error getting public key data: \(status)"); return nil } }
这里就是转换成PEM(X509的文件格式):
func exportKeyFromRawBytesAndShowInTextView(_ rawBytes: Data) { let keyType = getKeyTypeFromSegmentedControl() let keySize = getKeyLengthFromSegmentedControl() let exportImportManager = CryptoExportImportManager() if let exportableDERKey = exportImportManager.exportPublicKeyToDER(rawBytes, keyType: keyType, keySize: keySize) { self.textView.text = self.textView.text + "Exportable key in DER format:\n\(exportableDERKey.hexDescription)\n\n" print("Exportable key in DER format:\n\(exportableDERKey.hexDescription)\n") let exportablePEMKey = exportImportManager.PEMKeyFromDERKey(exportableDERKey) self.textView.text = self.textView.text + "Exportable key in PEM format:\n\(exportablePEMKey)\n\n" print("Exportable key in PEM format:\n\(exportablePEMKey)\n") } else { self.textView.text = self.textView.text + "Unable to generate DER key from raw bytes." } }
经过上面的步骤,就获得一串经过base64编码的string,如下:
Exportable key in PEM format: -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0CglywDQCmCdLNT8tiCJm75poZQo f2w+zdKCtyphK5LEgbWC8RUYojgFU0AEDdBVT5U4fBZwjBkjOnzCGCQEAQ== -----END PUBLIC KEY-----
切去"-----BEGIN PUBLIC KEY-----""-----END PUBLIC KEY-----"然后传给java,java用base64 decode,获得byte[],就可以顺利generate出public key.
**注意:这个库也有个缺憾,就是没有192的曲线头
private let kCryptoExportImportManagerSecp256r1CurveLen = 256 private let kCryptoExportImportManagerSecp256r1header: [UInt8] = [0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00] private let kCryptoExportImportManagerSecp256r1headerLen = 26
所以暂时转换不了192的曲线.
附加:使用openssl命令生成的PEM,取出string也可以转给java,不过ios的openssl库没有EC加密,只有RSA.所以这里不用openssl库.
补充:后来看到有同事使用cocopod来引用了openssl的库,应该是有生成EC曲线的API的,但还没尝试.
三.有可能有坑的地方:
首先,这样ios生成出来的PEM可以转换成java,但是打印发现java的key pair长度是91,但是ios的是123.后来发现第三方库生成的public key raw byte长度也是91,但是原封代码嵌入到我的项目中就不知道为什么出现123长度.而且这个长度base64 decode后也是可以转成java的public key的,十分神奇.
四.签名:
1.首先一下这篇文章介绍了如何进行非对称加密和签名和认证:
https://digitalleaves.com/blog/2015/10/asymmetric-cryptography-in-swift/
GitHub:https://github.com/DigitalLeaves/AsymmetricCrypto
我使用的也是上面这个库的签名方法.
这是Apple的签名guide:https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/signing_and_verifying?language=objc
以下是代码:
func signWithPrivate(_ text: String) -> String?{ let privateKey: SecKey = self.getPrivateKeyReference("your generate tag")! if #available(iOS 10.0, *) { let algorithm: SecKeyAlgorithm = .ecdsaSignatureMessageX962SHA1 guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else { print("Can't not sign") return nil } var error: Unmanaged<CFError>? let data = text.data(using: String.Encoding.utf8) guard let signature = SecKeyCreateSignature(privateKey, algorithm, data! as CFData, &error) as Data? else { print("Sign fail") return nil } // let sign = String(data: signature.base64EncodedData() as Data, encoding: String.Encoding.utf8) return signature.base64EncodedString() } else { let signature = self.signWithPrivateKeyUnderIOS10("Test123", privateKey) return signature } } private func signWithPrivateKeyUnderIOS10(_ text: String, _ key: SecKey) -> String? { var digest = Data(count: Int(CC_SHA1_DIGEST_LENGTH)) let data = text.data(using: .utf8)! let _ = digest.withUnsafeMutableBytes { digestBytes in data.withUnsafeBytes { dataBytes in CC_SHA1(dataBytes, CC_LONG(data.count), digestBytes) } } var signature = Data(count: SecKeyGetBlockSize(key) * 4) var signatureLength = signature.count let result = signature.withUnsafeMutableBytes { signatureBytes in digest.withUnsafeBytes { digestBytes in SecKeyRawSign(key, SecPadding.PKCS1SHA1, digestBytes, digest.count, signatureBytes, &signatureLength) } } let count = signature.count - signatureLength signature.removeLast(count) guard result == noErr else { return nil; } // let str123 = String(data: signature.base64EncodedData() as Data, encoding: String.Encoding.utf8) // return str123 return signature.base64EncodedString() }
上面的方法需要在ios10以上使用,下面的是适配ios10以下.签名后是base64编码了的,java那边验证的话也是需要先对这个签名进行解码.
另外需要重点说明一下,如果需要加密的内容含有类等元素,直接转成string来签名,签名后是验证不上的.因为转string过程中失真了.这个时候就需要编码一下,把要签名的内容先编码,然后再签名,这样最稳妥.那么对于java那边,同样需要对content进行编码来进行签名内容核对.
相关推荐
Android&IOS&数据库&linux&网络等2020最全的开发&测试面试汇总—笔试面试知识整理
iOS开发介绍、心得、项目及相关练习文章介绍 本文是一篇全面介绍iOS开发的文章,旨在帮助读者了解iOS开发的基本...最后,文章提供了一些与iOS开发相关的练习建议。这些练习涵盖了基础语法和控件、网络请求和数据解析、
ios 真机调试包11.0&11;.1,下载后拷贝到Xcode->Contents->Developer->Platforms->iPhoneOS.platform->DeviceSupport,然后重启Xcode
在iOS开发中,数据处理是不可或缺的一部分,而字典与模型之间的转换经常涉及到对象的序列化和反序列化。MJExtension就是这样一个专为iOS设计的轻量级框架,它极大地简化了字典到模型(Dictionary to Model)以及模型...
Learn how to make iPhone and iPad apps from the ground up, with a series of epic-length tutorials for beginners!...Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
ios 真机调试包6.0&6.1,下载后拷贝到Xcode->Contents->Developer->Platforms->iPhoneOS.platform->DeviceSupport,然后重启Xcode
A book on creating delightful iOS animations in Swift! From beginning to advanced topics like layer animations, view controller transitions, and more. Currently updated to: Platform: iOS13; Language: ...
本主题“JAVA与IOS加解密”主要关注如何在JAVA服务端和iOS客户端之间进行安全的数据交换,确保信息在传输过程中的隐私性和完整性。 一、JAVA加解密 JAVA提供了多种加解密算法,包括但不限于AES(高级加密标准)、...
Take control of your data in iOS apps using Core Data, Apple’s powerful object graph and persistence framework. Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
2D Apple Games by Tutorials Beginning 2D iOS, tvOS, macOS & watchOS Game Development with Swift 3 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有...
这个“ios 消息推送 java后端demo”是为开发者提供的一个示例,帮助理解如何使用Java后端实现对iOS设备的消息推送。下面将详细介绍iOS消息推送的原理、Java后端实现以及压缩包中可能包含的内容。 一、iOS消息推送...
Implement modern, clean architectures in your iOS apps! Currently updated to: Platform: iOS13; Language: Swift5.1; Editor: Xcode11
Beginning programming ... This book takes you from beginner to advanced in Swift: Apple’s modern programming language for iOS. Currently updated to: Platform: iOS13; Language: Swift5.1; Editor: Xcode11
Learn how to implement the most common and useful data structures and algorithms in Swift! Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
Master push notifications on iOS! Currently updated to: Platform: iOS13; Language: Swift5.1; Editor: Xcode11
本篇文章将深入探讨如何在Java服务端实现与APNs的集成,为iOS应用提供推送功能。 首先,我们需要理解APNs的工作原理。APNs是苹果提供的一个基于TCP/IP协议的推送服务,它允许服务器将消息推送到已注册的iOS设备。...
In this book, you'll master Core Data in iOS using Swift. Comprehensive coverage of Core Data, from beginner to advanced topics. Covers setting up a Core Data Stack, data modeling, versioning and ...
The book that teaches you to write maintainable and sustainable apps by building them with testing in mind or adding tests to... Currently updated to: Platform: iOS13; Language: Swift5.1; Editor: Xcode11
基于最新的XCUITEST框架的iOS自动化测试介绍,关键技术包含: appium,xcuitest,app-inspector,iOS自动化测试环境搭建
本示例“iOS根据java时间戳计算时间的demo”将指导开发者如何有效地进行这种转换,以便在iOS应用中正确展示日期和时间。这里我们将深入探讨iOS中的时间戳处理和UITextField的accessoryView配置。 首先,让我们来...