swift 使用 Diffie Hellman 密钥交换和椭圆曲线加密进行加密
Encryption in swift using Diffie Hellman key exchange and an elliptic curve encryption
我一直在尝试使用 Diffie Hellman 密钥交换和椭圆曲线加密来加密和解密 swift 中的字符串。
以下是我遵循的代码。
SWIFT代码:
let attributes: [String: Any] = [kSecAttrKeySizeInBits as String: 256,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false]]
var error: Unmanaged<CFError>?
if #available(iOS 10.0, *) {
**// Step 1: Generating the Public & Private Key**
guard let privateKey1 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {return false}
let publicKey1 = SecKeyCopyPublicKey(privateKey1)
guard let privateKey2 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {return false}
let publicKey2 = SecKeyCopyPublicKey(privateKey2)
let dict: [String: Any] = [:]
**// Step 2: Generating Shared Key**
guard let shared1 = SecKeyCopyKeyExchangeResult(privateKey1, SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256, publicKey2!, dict as CFDictionary, &error) else {return false}
**// Step 3: Encrypt string using Sharedkey**
let options: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeySizeInBits as String : 256]
// Stuck from this line on
guard let key = SecKeyCreateWithData(shared1 ,
options as CFDictionary,
&error) else {return false}
print(key)
let str = "Hello"
let byteStr: [UInt8] = Array(str.utf8)
let cfData = CFDataCreate(nil, byteStr, byteStr.count)
guard let encrypted = SecKeyCreateEncryptedData(publicKey1!,
SecKeyAlgorithm.ecdsaSignatureDigestX962SHA256,
cfData!,
&error) else {return false}
print(encrypted)
} else {
print("unsupported")
}
JAVA代码:
public static Map<String, Object> ecEncrypt(String deviceData, String serverPubKey, String dsTranID)
throws DataEncryptionException {
provider = new BouncyCastleProvider();
HashMap<String, Object> result = null;
JWEObject jweObject = null;
JWK jwk = null;
SecretKey Z = null;
JWEHeader header = null;
ECPublicKey ecpubkey = null;
byte[] byte_pubkey = null;
try {
result = new HashMap<String, Object>();
/*
* Generate Ephemeral keypair for SDk which constitute Public and
* Private key of SDK
*/
STEP 1:
sdkKeyPair = Crypto.generateEphemeralKeyPair();
/*
* Compute Secrete Key Z from SDKs Private Key(pSDK),DS Public
* key(serverPubKey) and DS ID
*/
//converting string to Bytes
STEP 2:
byte_pubkey = Base64.decode(serverPubKey, android.util.Base64.DEFAULT);
//converting it back to EC public key
STEP 3:
KeyFactory factory = KeyFactory.getInstance("ECDSA", provider);
ecpubkey = (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(byte_pubkey));
System.out.println("FINAL OUTPUT" + ecpubkey);
STEP 4:
Z = Crypto.generateECDHSecret(ecpubkey,
(ECPrivateKey) sdkKeyPair.getPrivate(), dsTranID,
"A128CBC_HS256");
System.out.println("****Secrete key Z for SDK Computed succesfully *****");
/*
* Build JWK to construct header
*/
STEP 5:
jwk = new ECKey.Builder(Curve.P_256,
(ECPublicKey) sdkKeyPair.getPublic()).build();
STEP 6:
header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES,
EncryptionMethod.A128CBC_HS256).ephemeralPublicKey(
ECKey.parse(jwk.toJSONString())).build();
System.out.println("****Header for SDK Computed succesfully*****");
/*
* Add Header and payload before encrypting payload using secret key
* Z
*/
STEP 7:
jweObject = new JWEObject(header, new Payload(deviceData));
jweObject.encrypt(new DirectEncrypter(Z));
/*
* serialize JWEobject which contains
* [header-base64url].[encryptedKey
* -base64url].[iv-base64url].[cipherText
* -base64url].[authTag-base64url]
*/
System.out
.println("****Payload of SDK encrypted succesfully *****");
return result;
} catch (Exception e) {
e.printStackTrace();
throw new DataEncryptionException();
} finally {
sdkKeyPair = null;
jweObject = null;
jwk = null;
Z = null;
header = null;
}
}
我也包含了 Java 代码。我必须在 Swift 中做同样的事情。如何使用共享密钥(Shared1)加密字符串进行EC加密?我需要执行第 3 步。有人可以帮忙吗?
首先,您正在尝试实施 ECIES。如果您想查找有关该计划的信息,知道实际名称很重要。
因此,假设密钥对 1 来自密文的发送方,密钥对 2 来自密文的接收方。在这种情况下,密钥对 1 应该是临时的(当场创建,绑定到一个加密的消息)并且密钥对 2 是静态的(预先创建并保存)。此外,public 密钥 2 被信任来自接收方。从您的简化代码中,这一切都不清楚,在您的代码中,您仍然可以切换发送方和接收方。
因此,使用接收方的 public 密钥 (2),发送方可以使用他们的私钥创建共享密钥,在您的代码中称为 shared1
。您现在可以使用 shared1
对数据进行对称加密。然后您只需将发送方的临时 public 密钥和密文发送给接收方。接收方使用发送方 (1) 的 public 密钥及其静态私钥 (2) 创建 shared2
。这与 shared1
相同,因此可以用作解密数据的密钥。
就是这样,除了要注意,由于发送方的私钥 (1) 与数据相关联,所以一旦 shared1
计算出来就不再需要它了,甚至可能会被丢弃在消息被加密之前。
如果您阅读了上面的内容,您就会发现将所有这些都集中在一个方法中并不是一个好主意:
- 创建接收方的静态密钥对;
- 将接收方的 public 密钥发送给发送方,并确保发送方可以信任来自接收方的 public 密钥(例如使用证书基础设施);
现在加密发送:
- 创建发送方的密钥对;
- 导出对称密钥;
- 丢掉私钥;
- 加密数据;
- 发送public密钥和数据;
接收方:
- 使用私钥推导出对称密钥;
- 解密数据。
就是这样。您可能希望在您的代码中显式这些步骤。
我一直在尝试使用 Diffie Hellman 密钥交换和椭圆曲线加密来加密和解密 swift 中的字符串。
以下是我遵循的代码。
SWIFT代码:
let attributes: [String: Any] = [kSecAttrKeySizeInBits as String: 256,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false]]
var error: Unmanaged<CFError>?
if #available(iOS 10.0, *) {
**// Step 1: Generating the Public & Private Key**
guard let privateKey1 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {return false}
let publicKey1 = SecKeyCopyPublicKey(privateKey1)
guard let privateKey2 = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {return false}
let publicKey2 = SecKeyCopyPublicKey(privateKey2)
let dict: [String: Any] = [:]
**// Step 2: Generating Shared Key**
guard let shared1 = SecKeyCopyKeyExchangeResult(privateKey1, SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256, publicKey2!, dict as CFDictionary, &error) else {return false}
**// Step 3: Encrypt string using Sharedkey**
let options: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeySizeInBits as String : 256]
// Stuck from this line on
guard let key = SecKeyCreateWithData(shared1 ,
options as CFDictionary,
&error) else {return false}
print(key)
let str = "Hello"
let byteStr: [UInt8] = Array(str.utf8)
let cfData = CFDataCreate(nil, byteStr, byteStr.count)
guard let encrypted = SecKeyCreateEncryptedData(publicKey1!,
SecKeyAlgorithm.ecdsaSignatureDigestX962SHA256,
cfData!,
&error) else {return false}
print(encrypted)
} else {
print("unsupported")
}
JAVA代码:
public static Map<String, Object> ecEncrypt(String deviceData, String serverPubKey, String dsTranID)
throws DataEncryptionException {
provider = new BouncyCastleProvider();
HashMap<String, Object> result = null;
JWEObject jweObject = null;
JWK jwk = null;
SecretKey Z = null;
JWEHeader header = null;
ECPublicKey ecpubkey = null;
byte[] byte_pubkey = null;
try {
result = new HashMap<String, Object>();
/*
* Generate Ephemeral keypair for SDk which constitute Public and
* Private key of SDK
*/
STEP 1:
sdkKeyPair = Crypto.generateEphemeralKeyPair();
/*
* Compute Secrete Key Z from SDKs Private Key(pSDK),DS Public
* key(serverPubKey) and DS ID
*/
//converting string to Bytes
STEP 2:
byte_pubkey = Base64.decode(serverPubKey, android.util.Base64.DEFAULT);
//converting it back to EC public key
STEP 3:
KeyFactory factory = KeyFactory.getInstance("ECDSA", provider);
ecpubkey = (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(byte_pubkey));
System.out.println("FINAL OUTPUT" + ecpubkey);
STEP 4:
Z = Crypto.generateECDHSecret(ecpubkey,
(ECPrivateKey) sdkKeyPair.getPrivate(), dsTranID,
"A128CBC_HS256");
System.out.println("****Secrete key Z for SDK Computed succesfully *****");
/*
* Build JWK to construct header
*/
STEP 5:
jwk = new ECKey.Builder(Curve.P_256,
(ECPublicKey) sdkKeyPair.getPublic()).build();
STEP 6:
header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES,
EncryptionMethod.A128CBC_HS256).ephemeralPublicKey(
ECKey.parse(jwk.toJSONString())).build();
System.out.println("****Header for SDK Computed succesfully*****");
/*
* Add Header and payload before encrypting payload using secret key
* Z
*/
STEP 7:
jweObject = new JWEObject(header, new Payload(deviceData));
jweObject.encrypt(new DirectEncrypter(Z));
/*
* serialize JWEobject which contains
* [header-base64url].[encryptedKey
* -base64url].[iv-base64url].[cipherText
* -base64url].[authTag-base64url]
*/
System.out
.println("****Payload of SDK encrypted succesfully *****");
return result;
} catch (Exception e) {
e.printStackTrace();
throw new DataEncryptionException();
} finally {
sdkKeyPair = null;
jweObject = null;
jwk = null;
Z = null;
header = null;
}
}
我也包含了 Java 代码。我必须在 Swift 中做同样的事情。如何使用共享密钥(Shared1)加密字符串进行EC加密?我需要执行第 3 步。有人可以帮忙吗?
首先,您正在尝试实施 ECIES。如果您想查找有关该计划的信息,知道实际名称很重要。
因此,假设密钥对 1 来自密文的发送方,密钥对 2 来自密文的接收方。在这种情况下,密钥对 1 应该是临时的(当场创建,绑定到一个加密的消息)并且密钥对 2 是静态的(预先创建并保存)。此外,public 密钥 2 被信任来自接收方。从您的简化代码中,这一切都不清楚,在您的代码中,您仍然可以切换发送方和接收方。
因此,使用接收方的 public 密钥 (2),发送方可以使用他们的私钥创建共享密钥,在您的代码中称为 shared1
。您现在可以使用 shared1
对数据进行对称加密。然后您只需将发送方的临时 public 密钥和密文发送给接收方。接收方使用发送方 (1) 的 public 密钥及其静态私钥 (2) 创建 shared2
。这与 shared1
相同,因此可以用作解密数据的密钥。
就是这样,除了要注意,由于发送方的私钥 (1) 与数据相关联,所以一旦 shared1
计算出来就不再需要它了,甚至可能会被丢弃在消息被加密之前。
如果您阅读了上面的内容,您就会发现将所有这些都集中在一个方法中并不是一个好主意:
- 创建接收方的静态密钥对;
- 将接收方的 public 密钥发送给发送方,并确保发送方可以信任来自接收方的 public 密钥(例如使用证书基础设施);
现在加密发送:
- 创建发送方的密钥对;
- 导出对称密钥;
- 丢掉私钥;
- 加密数据;
- 发送public密钥和数据;
接收方:
- 使用私钥推导出对称密钥;
- 解密数据。
就是这样。您可能希望在您的代码中显式这些步骤。