【问题标题】:Fernet encryption/decryption with python and kotlin使用 python 和 kotlin 进行 Fernet 加密/解密
【发布时间】:2021-02-15 02:13:33
【问题描述】:

我有一个用 python 编写的项目。我使用密码库来加密和解密数据。 我按照他们的tutorial 显示的方式进行操作。

这是我的python代码:

import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

password = b"my password"
salt = os.urandom(16)

kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),
                 length=32,
                 salt=salt,
                 iterations=100000,
                 backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)
data = b"my data..."
token = f.encrypt(data)

然后我可以使用解密:

f.decrypt(token)

一切都在 python 中完美运行,但现在我需要在 kotlin 中做同样的事情。我发现了 fernet java-8 库,但我不知道如何以同样的方式使用它。

问题是我有两个工具:一个是用 python 编写的,另一个是我想用 kotlin 编写的。这两种工具都是为了做同样的事情——python 一个用于桌面,而 kotlin 一个将是一个 android 应用程序。因此,它们的加密相同非常重要,以便在 python(桌面工具)中加密的文件可以在 kotlin(android 应用程序)中解密,反之亦然。

但我不知道如何编写类似的 kotlin 代码。

您会看到有一个名为PBKDF2HMAC 的函数(或类),还有base64.urlsafe_b64encode 等。而且我不知道 kotlin 或 fernet java-8 中的类似函数是什么。

那我该怎么做呢?假设在 kotlin 中我必须使用我在 python 中使用的密码和盐。

谢谢!

【问题讨论】:

    标签: python android kotlin encryption fernet


    【解决方案1】:

    在 Java/Kotlin 中,使用fernet-java8,使用 Python 代码生成的令牌可以解密如下:

    import java.security.SecureRandom
    import java.util.Base64
    import javax.crypto.spec.PBEKeySpec
    import javax.crypto.SecretKeyFactory
    import com.macasaet.fernet.Key
    import com.macasaet.fernet.Token
    import com.macasaet.fernet.StringValidator
    import com.macasaet.fernet.Validator
    import java.time.Duration
    import java.time.temporal.TemporalAmount
    
    ...
    
    // Data from encryption
    val salt = Base64.getUrlDecoder().decode("2Yb8EwpYkMlycHxoKcmHuA==")
    val token = Token.fromString("gAAAAABfoAmp7C7IWVgA5urICEIspm_MPAGZ-SyGnPEVUBBNerWQ-K6mpSoYTwRkUt3FobyAFHbYfhNtiGMe_96yyLvUoeLIIg==");
    
    // Derive Fernet key
    val key = deriveKey("my password", salt)
    val fernetKey = Key(key)
    
    // Decrypt
    val validator: Validator<String> = object : StringValidator {
        override fun getTimeToLive(): TemporalAmount {
            return Duration.ofHours(24)
        }
    }
    val data = token.validateAndDecrypt(fernetKey, validator)
    println(data) // my data...
    

    与:

    fun deriveKey(password: String, salt: ByteArray): String {
        val iterations = 100000
        val derivedKeyLength = 256
        val spec = PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength)
        val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
        val key = secretKeyFactory.generateSecret(spec).encoded
        return Base64.getUrlEncoder().encodeToString(key)
    }
    

    这里的 Fernet 密钥是使用密钥派生函数PBKDF2 派生的。 PBKDF2 需要各种输入参数,例如密码、摘要、盐、迭代计数和所需的密钥长度。在发布的示例中,密钥返回 Base64url 编码。
    对于解密,必须使用与加密相同的参数。由于盐通常(如在发布的代码中)在加密期间随机生成,因此必须将其与密文一起传递给解密方(注意:盐不是秘密)。

    验证器将生存时间(默认为 60 秒)设置为 24 小时,有关详细信息,请参阅 here

    在发布的 Python 代码中,必须添加盐的导出,例如通过 Base64url 对其进行编码,类似于密钥和令牌(并为简单起见打印它)。在实践中,salt 和 token 也可以在加密时连接,在解密时分离。

    更新:

    加密部分类似:

    // Generate salt
    val salt = generateSalt()
    println(Base64.getUrlEncoder().encodeToString(salt))
    
    // Derive Fernet key
    val key = deriveKey("my password", salt)
    val fernetKey = Key(key)
    
    // Encrypt
    val data = "my data..."
    val token = Token.generate(fernetKey, data)
    println(token.serialise()) // the Base64url encoded token
    

    fun generateSalt(): ByteArray {
        val random = SecureRandom()
        val salt = ByteArray(16)
        random.nextBytes(salt)
        return salt
    }
    

    【讨论】:

    • 非常感谢!我还没有测试它,但它看起来很有希望!当我测试它时,我会将你的答案标记为正确的。还要感谢这一点:“注意:盐不是秘密”,因为有时我会怀疑将盐按原样存放而不是存放在安全的地方。
    • @Acmpo6ou - 因为问题是用 Kotlin 标记的,所以我将 Java 代码移植到 Kotlin(如果有人需要,可以从历史记录中检索 Java 代码)。
    • 感谢您将所有代码重写为 Kotlin,您真的帮助了我!
    猜你喜欢
    • 2022-12-30
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    相关资源
    最近更新 更多