【问题标题】:Convert Java Decrypt to Swift将 Java 解密转换为 Swift
【发布时间】:2021-02-22 22:24:17
【问题描述】:

我正在尝试将一段 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, 0, bArr, 0, 16);
        System.arraycopy(doFinal, 16, bArr2, 0, 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。

有人可以帮我解决这个问题吗?

【问题讨论】:

  • Stack Overflow 不是代码编写服务。如果您能提供一些关于您当前遇到的什么问题、您尝试过什么以及遇到什么问题的详细信息,将会有所帮助。

标签: swift encryption rsa decode commoncrypto


【解决方案1】:

看起来好像有以下场景:

  • 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 脚本中相同的密钥二进制输出。

对于十六进制数据的输出,我们可以使用这个很好的答案中的函数hexDescriptionhttps://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, 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)
    }
    
}


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, 0, bArr, 0, 16);
            System.arraycopy(doFinal, 16, bArr2, 0, 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 程序提供了相同的结果。

【讨论】:

  • 感谢 Stephan 的超级响应以及您所做的辛勤工作,我目前正在尝试实现您的代码并尝试执行后续步骤,让我们看看是否可以...祈祷!! :)
  • 我已经完成了整个流程......再次感谢您的大力帮助!!!
猜你喜欢
  • 2020-06-08
  • 1970-01-01
  • 2017-09-25
  • 1970-01-01
  • 2023-02-20
  • 2019-06-06
  • 1970-01-01
  • 2012-09-23
相关资源
最近更新 更多