问题描述
我正在尝试将Java代码块转换为Swift,但是我没有得到
这是我要转换的块:
https://github.com/K4CZP3R/tapo-p100-java-poc/blob/main/src/main/java/KspEncryption.java
public static C658a decodeTapoKey(String key,KspKeyPair keyPair) {
KspDebug.out("Will try to decode the following key: " + key);
try {
byte[] decode = KspB64.decode(key.getBytes("UTF-8"));
byte[] decode2 = KspB64.decode(keyPair.getPrivateKey());
Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey p = kf.generatePrivate(new PKCS8EncodedKeySpec(decode2));
instance.init(Cipher.DECRYPT_MODE,p);
byte[] doFinal = instance.doFinal(decode);
byte[] bArr = new byte[16];
byte[] bArr2 = new byte[16];
System.arraycopy(doFinal,bArr,16);
System.arraycopy(doFinal,16,bArr2,16);
return new C658a(bArr,bArr2);
}
catch (Exception ex)
{
KspDebug.out("Something went wrong: " + ex.getMessage());
return null;
}
}
这里是相同的代码,但是这次是在Python中: https://github.com/K4CZP3R/tapo-p100-python/blob/21e4bf9b61c08a3eb215293198968f82cd80ab2d/encryption.py
def decode_handshake_key(key: str,key_pair: KeyPair) -> TpLinkCipher:
logger.debug(f"Will decode handshake key (...{key[5:]}) using current key pair")
decode: bytes = base64.b64decode(key.encode("UTF-8"))
decode2: bytes = base64.b64decode(key_pair.get_private_key())
cipher = PKCS1_v1_5.new(RSA.import_key(decode2))
do_final = cipher.decrypt(decode,None)
if do_final is None:
raise ValueError("Decryption Failed!")
b_arr:bytearray = bytearray()
b_arr2:bytearray = bytearray()
for i in range(0,16):
b_arr.insert(i,do_final[i])
for i in range(0,16):
b_arr2.insert(i,do_final[i + 16])
这是我现在在Swift中不正确的内容
func decodeTapoKey(key: String,keyPair: KspKeyPair) {
let data = key.data(using: .utf8)!
let b64 = data.base64EncodedString(options: .lineLength76Characters)
let data2 = keyPair.privateKey.data(using: .utf8)!
let b642 = data2.base64EncodedString(options: .lineLength76Characters)
do {
let privateKey = try PrivateKey(pemNamed: keyPair.getPrivateKey())
let encrypted = try EncryptedMessage(base64Encoded: key)
let clear = try encrypted.decrypted(with: privateKey,padding: .PKCS1)
// Then you can use:
let data = clear.data
let base64String = clear.base64String
let string = try clear.string(encoding: .utf8)
} catch {
print("error")
}
我正在尝试使用Pod SwiftyRSA。
有人可以帮我吗?
解决方法
似乎有以下情况:
- 一个32字节的对称密钥,在服务器端以base64格式生成
- 此32字节的密钥在服务器端已使用客户端的公共密钥加密
- 要在客户端解密,需要使用客户端的私钥,该私钥似乎是用PKCS8格式进行base64编码的
在客户端,我们可以:
- 用密钥构造一个EncryptedMessage
- 创建一个PrivateKey实例
- 随后使用私钥解密邮件
- 然后将结果分为两个数据实例,每个数据实例各16个字节,如问题示例所示
此函数的源代码如下所示:
static func decodeTapoKey(key: String,keyPair: KspKeyPair) throws -> (Data,Data) {
let keyWithoutWhiteSpaces = String(key.compactMap { $0.isWhitespace ? nil : $0 })
let encrypted = try EncryptedMessage(base64Encoded: keyWithoutWhiteSpaces)
let privateKey = try PrivateKey(base64Encoded: keyPair.privateKey)
let decryptedKey = try encrypted.decrypted(with: privateKey,padding: SecPadding.PKCS1)
let b_arr = decryptedKey.data[0..<16]
let b_arr2 = decryptedKey.data[16..<32]
return (b_arr,b_arr2)
}
测试
一个人可以生成一个私有和公共测试密钥以及一个256位(= 32字节)的AES密钥。有了这些数据,我们应该获得与Python脚本相同的密钥二进制输出。
对于十六进制数据的输出,我们可以使用以下正确答案中的函数hexDescription
:https://stackoverflow.com/a/39075044。
一个完全独立的示例:
Decrypt.swift
import Foundation
import SwiftyRSA
struct KspKeyPair {
let privateKey: String
let publicKey: String
}
final class Decrypt {
static func decodeTapoKey(key: String,Data) {
let keyWithoutWhiteSpaces = String(key.compactMap { $0.isWhitespace ? nil : $0 })
let encrypted = try EncryptedMessage(base64Encoded: keyWithoutWhiteSpaces)
let privateKey = try PrivateKey(base64Encoded: keyPair.privateKey)
let decryptedKey = try encrypted.decrypted(with: privateKey,padding: SecPadding.PKCS1)
let b_arr = decryptedKey.data[0..<16]
let b_arr2 = decryptedKey.data[16..<32]
return (b_arr,b_arr2)
}
}
extension Data {
var hexDescription: String {
return reduce("") {$0 + String(format: "%02x",$1)}
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
let privateKey =
"""
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMY+gDb9hwm9gmYB+iDYxKPngQ3X
Rm3U4tzea9NLtmHgWipM44tE4zWkEeaBawWbFjrnT0lPriTXPn6OvvDRCY7eRejB9wP/aezoNMMr
A2XQ6Du8gcopM1ylUJCWjr9nftTb6wn75wY5IMPUKM2N0uZ+dvfQH4qEQwE05z6Iz1szAgMBAAEC
gYAW5UcHktZSwKlbwKSzwHVNfMJB5/gBXVHqMmH/oEHrIe8n7YNmJUmce1t55L6IgjXaDbbxf5tc
M+PK2A+jXnEc8+2snDbI1PpBepEwg5vzZ8RYnhGZT6P0/PsIqInkTIZnfXDnQ6wBapO1m9xJDe/B
fyWMVRa6JqJtgQ0XpfG76QJBAOgKPSF5wJKC69lCbvyh38fQoeJxEKrD03FGXGBDLLYOHqfijdMT
vcnE415994MI3fTy2dWm/yB8wZ7DvYVwVX8CQQDatuZyi6LhLhU47l5vpFsOnRWGhGrZaIN0o7N/
1v5Vwieujrwy/yW2uCvUeXVnmohJa+sFSr29HO4PEQwWtFxNAkBXSxrKUDJ5K9Wsa0izs/YrBrsQ
JDb/9yHBmJXCBSN57f/sateuE9wvXummr78AxcIyl3YJ4YRTZXu1za+r1qHjAkEAzjkavPKQ18W9
2PpZLOdJvFO9EiMVJH15Rad8/pNXKMFy7RJEvcj6ZHjvSt5jJxb8Xk5VQZ4hnYkDpk0qmtXhGQJB
AIO6TEXkHU3Sn0qTZsPmpu+EfCADLNKG43kiv74+cRzS7Th2A6E1yq5Y/lmbdpYaHqm0mKgvMHb2
ls7DtRTYoXo=
"""
let publicKey =
"""
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGPoA2/YcJvYJmAfog2MSj54EN10Zt1OLc3mvT
S7Zh4FoqTOOLROM1pBHmgWsFmxY6509JT64k1z5+jr7w0QmO3kXowfcD/2ns6DTDKwNl0Og7vIHK
KTNcpVCQlo6/Z37U2+sJ++cGOSDD1CjNjdLmfnb30B+KhEMBNOc+iM9bMwIDAQAB
"""
let secretKey =
"""
YyqsaPrgmVKcjS6UQY5aV0KtOdovqbuwGQMkZMoHtwygZQVy3fiLp0/03B4LKkYtIm0SBPYJw/cV
w2DyZYsPPvX71RbuU9Pp+AJkWTfReEWhSW2vonWv6HIULK94hREHt7S51oBNXo5QP4wn2F4PD3hg
P2DYBAw7guMy9wbGB+4=
"""
override func viewDidLoad() {
super.viewDidLoad()
let keyPair = KspKeyPair(privateKey: privateKey,publicKey: publicKey)
do {
let (b_arr,b_arr2) = try Decrypt.decodeTapoKey(key: secretKey,keyPair: keyPair)
print(b_arr.hexDescription)
print(b_arr2.hexDescription)
} catch {
print("decoding failed: \(error)")
}
}
}
输出为:
4907d77a736619e6338f7e88fbed565f
40decbd392295df33afa817d23ac2824
Python
基于您的Python脚本,还有一个完全独立的示例:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
import logging
from collections import namedtuple
KspKeyPair = namedtuple('KspKeyPair',['private_key','public_key'])
logger = logging.getLogger('root')
def decode_handshake_key(key: str,keyPair: KspKeyPair):
logger.debug(f"Will decode handshake key (...{key[5:]}) using current key pair")
decode: bytes = base64.b64decode(key.encode("UTF-8"))
decode2: bytes = base64.b64decode(keyPair.private_key)
cipher = PKCS1_v1_5.new(RSA.import_key(decode2))
do_final = cipher.decrypt(decode,None)
if do_final is None:
raise ValueError("Decryption failed!")
b_arr: bytearray = bytearray()
b_arr2: bytearray = bytearray()
for i in range(0,16):
b_arr.insert(i,do_final[i])
for i in range(0,16):
b_arr2.insert(i,do_final[i + 16])
print(b_arr.hex())
print(b_arr2.hex())
if __name__ == "__main__":
privateKey = """
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMY+gDb9hwm9gmYB+iDYxKPngQ3X
Rm3U4tzea9NLtmHgWipM44tE4zWkEeaBawWbFjrnT0lPriTXPn6OvvDRCY7eRejB9wP/aezoNMMr
A2XQ6Du8gcopM1ylUJCWjr9nftTb6wn75wY5IMPUKM2N0uZ+dvfQH4qEQwE05z6Iz1szAgMBAAEC
gYAW5UcHktZSwKlbwKSzwHVNfMJB5/gBXVHqMmH/oEHrIe8n7YNmJUmce1t55L6IgjXaDbbxf5tc
M+PK2A+jXnEc8+2snDbI1PpBepEwg5vzZ8RYnhGZT6P0/PsIqInkTIZnfXDnQ6wBapO1m9xJDe/B
fyWMVRa6JqJtgQ0XpfG76QJBAOgKPSF5wJKC69lCbvyh38fQoeJxEKrD03FGXGBDLLYOHqfijdMT
vcnE415994MI3fTy2dWm/yB8wZ7DvYVwVX8CQQDatuZyi6LhLhU47l5vpFsOnRWGhGrZaIN0o7N/
1v5Vwieujrwy/yW2uCvUeXVnmohJa+sFSr29HO4PEQwWtFxNAkBXSxrKUDJ5K9Wsa0izs/YrBrsQ
JDb/9yHBmJXCBSN57f/sateuE9wvXummr78AxcIyl3YJ4YRTZXu1za+r1qHjAkEAzjkavPKQ18W9
2PpZLOdJvFO9EiMVJH15Rad8/pNXKMFy7RJEvcj6ZHjvSt5jJxb8Xk5VQZ4hnYkDpk0qmtXhGQJB
AIO6TEXkHU3Sn0qTZsPmpu+EfCADLNKG43kiv74+cRzS7Th2A6E1yq5Y/lmbdpYaHqm0mKgvMHb2
ls7DtRTYoXo=
"""
publicKey = """
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGPoA2/YcJvYJmAfog2MSj54EN10Zt1OLc3mvT
S7Zh4FoqTOOLROM1pBHmgWsFmxY6509JT64k1z5+jr7w0QmO3kXowfcD/2ns6DTDKwNl0Og7vIHK
KTNcpVCQlo6/Z37U2+sJ++cGOSDD1CjNjdLmfnb30B+KhEMBNOc+iM9bMwIDAQAB
"""
secretKey = """
YyqsaPrgmVKcjS6UQY5aV0KtOdovqbuwGQMkZMoHtwygZQVy3fiLp0/03B4LKkYtIm0SBPYJw/cV
w2DyZYsPPvX71RbuU9Pp+AJkWTfReEWhSW2vonWv6HIULK94hREHt7S51oBNXo5QP4wn2F4PD3hg
P2DYBAw7guMy9wbGB+4=
"""
keyPair = KspKeyPair(privateKey,publicKey)
decode_handshake_key(secretKey,keyPair)
此Python程序的输出与iOS Swift程序的输出完全相同。因此,Swift部分似乎可以正常工作。
Java
对于Java例程,也应该给出相同的输出。让我们用这个独立的Java示例进行测试:
package com.software7;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class Main {
static String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMY+gDb9hwm9gmYB+iDYxKPngQ3XRm3U4tzea9NLtmHgWipM44tE4zWkEeaBawWbFjrnT0lPriTXPn6OvvDRCY7eRejB9wP/aezoNMMrA2XQ6Du8gcopM1ylUJCWjr9nftTb6wn75wY5IMPUKM2N0uZ+dvfQH4qEQwE05z6Iz1szAgMBAAECgYAW5UcHktZSwKlbwKSzwHVNfMJB5/gBXVHqMmH/oEHrIe8n7YNmJUmce1t55L6IgjXaDbbxf5tcM+PK2A+jXnEc8+2snDbI1PpBepEwg5vzZ8RYnhGZT6P0/PsIqInkTIZnfXDnQ6wBapO1m9xJDe/BfyWMVRa6JqJtgQ0XpfG76QJBAOgKPSF5wJKC69lCbvyh38fQoeJxEKrD03FGXGBDLLYOHqfijdMTvcnE415994MI3fTy2dWm/yB8wZ7DvYVwVX8CQQDatuZyi6LhLhU47l5vpFsOnRWGhGrZaIN0o7N/1v5Vwieujrwy/yW2uCvUeXVnmohJa+sFSr29HO4PEQwWtFxNAkBXSxrKUDJ5K9Wsa0izs/YrBrsQJDb/9yHBmJXCBSN57f/sateuE9wvXummr78AxcIyl3YJ4YRTZXu1za+r1qHjAkEAzjkavPKQ18W92PpZLOdJvFO9EiMVJH15Rad8/pNXKMFy7RJEvcj6ZHjvSt5jJxb8Xk5VQZ4hnYkDpk0qmtXhGQJBAIO6TEXkHU3Sn0qTZsPmpu+EfCADLNKG43kiv74+cRzS7Th2A6E1yq5Y/lmbdpYaHqm0mKgvMHb2ls7DtRTYoXo=";
static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGPoA2/YcJvYJmAfog2MSj54EN10Zt1OLc3mvTS7Zh4FoqTOOLROM1pBHmgWsFmxY6509JT64k1z5+jr7w0QmO3kXowfcD/2ns6DTDKwNl0Og7vIHKKTNcpVCQlo6/Z37U2+sJ++cGOSDD1CjNjdLmfnb30B+KhEMBNOc+iM9bMwIDAQAB";
static String secretKey = "YyqsaPrgmVKcjS6UQY5aV0KtOdovqbuwGQMkZMoHtwygZQVy3fiLp0/03B4LKkYtIm0SBPYJw/cVw2DyZYsPPvX71RbuU9Pp+AJkWTfReEWhSW2vonWv6HIULK94hREHt7S51oBNXo5QP4wn2F4PD3hgP2DYBAw7guMy9wbGB+4=";
public static void main(String[] args) {
KspKeyPair keyPair = new KspKeyPair(privateKey,publicKey);
C658a result = decodeTapoKey(secretKey,keyPair);
System.out.println(Hex.encodeHexString(result.bArr));
System.out.println(Hex.encodeHexString(result.bArr2));
}
public static C658a decodeTapoKey(String key,KspKeyPair keyPair) {
try {
byte[] decode = KspB64.decode(key.getBytes("UTF-8"));
byte[] decode2 = KspB64.decode(keyPair.getPrivateKey());
Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey p = kf.generatePrivate(new PKCS8EncodedKeySpec(decode2));
instance.init(Cipher.DECRYPT_MODE,p);
byte[] doFinal = instance.doFinal(decode);
byte[] bArr = new byte[16];
byte[] bArr2 = new byte[16];
System.arraycopy(doFinal,bArr,16);
System.arraycopy(doFinal,16,bArr2,16);
return new C658a(bArr,bArr2);
} catch (Exception ex) {
System.out.println("Something went wrong: " + ex.getMessage());
return null;
}
}
}
class C658a {
byte[] bArr;
byte[] bArr2;
public C658a(byte[] bArr,byte[] bArr2) {
this.bArr = bArr;
this.bArr2 = bArr2;
}
}
class KspKeyPair {
String privateKey;
String publicKey;
public KspKeyPair(String privateKey,String publicKey) {
this.privateKey = privateKey;
this.publicKey = publicKey;
}
public byte[] getPrivateKey() { return privateKey.getBytes(); }
public byte[] getPublicKey() { return publicKey.getBytes(); }
}
class KspB64 {
public static byte[] decode(byte[] bytes) {
return Base64.getMimeDecoder().decode(bytes);
}
}
Java程序确实提供了相同的结果。