Java中的iOS CryptoKit

2020年11月4日 49点热度 0条评论

我正在寻找CryptoKit的设置/参数,该设置/参数将允许我在iOS App和Java Application之间共享数据。流程如下所示:
-使用CryptoKit通过固定密钥和随机初始化向量(IV)加密文本。
-在Java应用程序中,使用标准javax库使用相同的固定密钥执行解密。随机IV和加密的文本将与应用程序一起传输/共享。

同样,也需要相反的操作,其中使用JavaX库使用固定密钥和随机IV对文本进行加密。随机IV和加密文本与iOS应用共享,在iOS应用中应使用CryptoKit对其进行解密。

以下是Java中加密和解密的代码

public static byte[] encrypt(byte[] plaintext, byte[] key, byte[] IV) throws Exception
{
    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES_256/GCM/NoPadding");

    // Create SecretKeySpec
    SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

    // Create GCMParameterSpec
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);

    // Initialize Cipher for ENCRYPT_MODE
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);

    // Perform Encryption
    byte[] cipherText = cipher.doFinal(plaintext);

    return cipherText;
}

public static String decrypt(byte[] cipherText, byte[] key, byte[] IV) throws Exception
{
    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES_256/GCM/NoPadding");

    // Create SecretKeySpec
    SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

    // Create GCMParameterSpec
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);

    // Initialize Cipher for DECRYPT_MODE
    cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

    // Perform Decryption
    byte[] decryptedText = cipher.doFinal(cipherText);

    return new String(decryptedText);
}

CryptoKit命令如下:

let mykey = SymmetricKey(data: passhash)
let myiv = try AES.GCM.Nonce()
let mySealedBox = try AES.GCM.seal(source.data(using: .utf8)!, using: mykey, nonce: myiv)
let myNewSealedBox = try AES.GCM.SealedBox(nonce: myiv, ciphertext: mySealedBox.ciphertext, tag: mySealedBox.tag)
let myText = try String(decoding: AES.GCM.open(myNewSealedBox, using: mykey), as: UTF8.self)

以下是在Java中生成加密文本的步骤:

int GCM_IV_LENGTH = 12;

//Generate Key
MessageDigest md = MessageDigest.getInstance("SHA265");
byte[] key = md.digest("pass".getBytes(StandardCharsets.UTF_8));

// Generate IV
SecureRandom sr = new SecureRandom(pass.getBytes(StandardCharsets.UTF_8));
byte[] IV = new byte[GCM_IV_LENGTH];
sr.nextBytes(IV);

//Encrypt
byte[] cipherText = encrypt("Text to encrypt".getBytes(), key, IV);

//Base64 Encoded CipherText
String cipherTextBase64 = Base64.getEncoder().encodeToString(cipherText);

要在SWIFT CryptoKit中对此进行解密,我首先需要使用此CipherText创建一个密封盒,但是,用于创建密封盒的CryptoKit API需要满足以下条件:

  • Nonce / IV(以上可用)
  • CipherText(上面可用)
  • 标记(从何处获得此想法???)
  • AES.GCM.SealedBox(nonce: , ciphertext: , tag: )
    

    另一种方式,让我们首先在CryptoKit中加密数据

    let mykey = SymmetricKey(data: SHA256.hash(data: "12345".data(using: .utf8)!))
    let myiv = AES.GCM.Nonce()
    let mySealedBox = try AES.GCM.seal("Text to encrypt".data(using: .utf8)!, using: mykey, nonce: myiv)
    let cipherText = mySealedBox.cipherText.base64EncodedString()
    let iv = myiv.withUnsafeBytes{
        return Data(Array($0)).base64EncodedString()
    }
    

    如果我将此IV和CipherText与密钥(“12345”字符串的SHA265哈希)一起传递给Java Decrypt函数,则会收到TAG不匹配错误。

    解决方案如下:

    这是SWIFT中的最后一组代码:

    let pass = “Password”
    let data = “Text to encrypt”.data(using: .utf8)!
    let key = SymmetricKey(data: SHA256.hash(data: pass.datat(using: .utf8)!))
    let iv = AES.GCM.Nonce()
    let mySealedBox = try AES.GCM.seal(data, using: key, nonce: iv)
    dataToShare = mySealedBox.combined?.base64EncodedData()
    

    将此数据写入文件(我正在使用Google API将这些数据写入Google驱动器上的文件)

    使用以下代码从Java文件中读取此数据,并将其传递给问题中定义的函数:

    byte[] iv = Base64.getDecoder().decode(text.substring(0,16));
    cipher[] = Base64.getDecoder().decode(text.substring(16));
    byte[] key = md.digest(pass.getBytes(StandardCharsets.UTF_8));
    String plainText = decrypt(cipher, key, iv);