首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将药剂加密和解密逻辑映射到PHP,反之亦然

将药剂加密和解密逻辑映射到PHP,反之亦然
EN

Stack Overflow用户
提问于 2021-09-15 05:10:00
回答 2查看 183关注 0票数 2

我试图用Elixir和PHP编写逻辑来加密和解密文本。我的目标是解密用药剂加密的数据,反之亦然。这两种算法都工作得很好,但我遇到的唯一问题是将初始化向量与密码文本分离,并在PHP中将二进制文件转换为字符串,以及在Elixir中将解密文本转换为字符串。

Elixir实现:

代码语言:javascript
复制
    defmodule Crypto.AES do
    @block_size 16
    @secret_key "something secret here"

    def encrypt(text) do
        secret_key_hash = make_hash(@secret_key, 32)

        IO.inspect secret_key_hash

        # create random Initialisation Vector
        iv = :crypto.strong_rand_bytes(@block_size)

        text = pad_pkcs7(text, @block_size)
        encrypted_text = :crypto.crypto_one_time(:aes_256_cbc, secret_key_hash, iv, text, true )
        
        encrypted_text = ( iv <> <<"::">> <>  encrypted_text )
        
        Base.encode64(encrypted_text)
    end

    def decrypt(ciphertext) do
        secret_key_hash = make_hash(@secret_key, 32)

        {:ok, ciphertext} = Base.decode64(ciphertext)
        <<iv::binary-16, rp::binary-2, ciphertext::binary>> = ciphertext
        decrypted_text = :crypto.crypto_one_time(:aes_256_cbc, secret_key_hash, iv, ciphertext, false)

        unpad_pkcs7(decrypted_text)
    end
    
    @doc """
    Pad the `message` by extending it to the nearest `blocksize` boundary,
    appending the number of bytes of padding to the end of the block.
    If the original `message` is a multiple of `blocksize`, an additional block
    of bytes with value `blocksize` is added.
    """

    def pad_pkcs7(message, blocksize) do
        pad = blocksize - rem(byte_size(message), blocksize)
        message <> to_string(List.duplicate(pad, pad))
    end

    @doc """
    Remove the PKCS#7 padding from the end of `data`.
    """
    def unpad_pkcs7(data) do
        <<pad>> = binary_part(data, byte_size(data), -1)
        binary_part(data, 0, byte_size(data) - pad)
    end

    def make_hash(text, length) do
      :crypto.hash(:sha512, text)
        |> Base.encode16
        |> String.downcase
        |> String.slice(0, length)
    end

end

PHP实现:

代码语言:javascript
复制
    <?php
    $ENCRYPTION_KEY = 'something secret here';
    $ENCRYPTION_ALGORITHM = 'AES-256-CBC';

    function encrypt($plain_text) {
        global $ENCRYPTION_KEY;
        global $ENCRYPTION_ALGORITHM;
        $EncryptionKey = make_hash($ENCRYPTION_KEY, 32);

        // create random Initialisation Vector
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($ENCRYPTION_ALGORITHM));

        $encrypted_text = openssl_encrypt(
            $plain_text,
            $ENCRYPTION_ALGORITHM,
            $EncryptionKey,
            0,
            $iv
        );

        return  base64_encode($encrypted_text . '::' . $iv);
    }

    function decrypt($ciphertext) {
        global $ENCRYPTION_KEY;
        global $ENCRYPTION_ALGORITHM;
        $EncryptionKey = make_hash($ENCRYPTION_KEY, 32);

        $split = explode('::', base64_decode($ciphertext), 2);
        list($iv, $encrypted_text) = array_pad($split, 2, null);

        $plain_text = openssl_decrypt(
            $encrypted_text,
            $ENCRYPTION_ALGORITHM,
            $EncryptionKey,
            0,
            $iv
        );

        return $plain_text;
    }

    function make_hash($text, $length) {
        $hash_key = hash("sha512", $text, false);
        return substr($hash_key,0,$length);
    }

    $ct = encrypt("hello");
    // echo $ct."\n";
    echo decrypt("Sr4nMnMdDHhUQcnW6RwZ2Do6rhBh/ytW1W/x7Xx2/Xrv3A==")."\n";
?>

请提出一些可能的解决办法。谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-15 14:17:07

这两项守则是不相容的,原因有二:

  • PHP代码返回加密过程中默认编码的密文Base64。这必须禁用,因为Base64编码是在IV和密文连接后显式执行的。通过将OPENSSL_RAW_DATA作为openssl_encrypt()中的第四个参数传递,可以禁用。这同样适用于解密: $encrypted_text = openssl_encrypt( $plain_text,$ENCRYPTION_ALGORITHM,$EncryptionKey,OPENSSL_RAW_DATA,// Fix:不要Base64编码密文$iv );$plain_text = openssl_decrypt( $encrted_text,$ENCRYPTION_ALGORITHM,$EncryptionKey,OPENSSL_RAW_DATA,// Fix:不要Base64解码密文$iv );
  • 正如注释中已经指出的,这两种代码在解密期间分离时都假定了IV和密文的不同顺序。Menwhile您已经调整了PHP代码中解密期间的分离,使之与Elixir代码的分离相适应。 但是对于加密,这两种代码都使用了不同的IV和密文顺序。有关加密的PHP代码的修改仍未完成: ..。返回base64_encode($iv .“:”。( $encrypted_text);//反向顺序

通过这些更改,这两个代码在功能上是相同的,用PHP代码生成的密文可以用Elixir代码解密,反之亦然。

关于级联的注意事项: IV和密文都可以以一定的概率包含分隔符::,这可能会导致问题。最好是在没有分隔符的情况下将数据连接起来,并使用已知的IV长度进行分离。

此外,使用散列函数进行密钥派生是不安全的,最好应用可靠的密钥派生函数,如PBKDF2。此外,采用十六进制编码密钥而不是二进制数据降低了安全性。

票数 1
EN

Stack Overflow用户

发布于 2021-09-15 22:30:16

使用@Topaco的建议( PBKDF2除外,稍后将添加),这是完整的解决方案。

Elixir - git-链接

代码语言:javascript
复制
defmodule Crypto.AES do
    @block_size 16
    @secret_key "put something secret here"

    def encrypt(plain_text) do
        secret_key_hash = make_hash(@secret_key, 32)

        # create Initialisation Vector
        iv = :crypto.strong_rand_bytes(@block_size)

        padded_text = pad_pkcs7(plain_text, @block_size)
        encrypted_text = :crypto.crypto_one_time(:aes_256_cbc, secret_key_hash, iv, padded_text, true )
        
        # concatenate IV for decryption
        encrypted_text = ( iv <>  encrypted_text )
        
        Base.encode64(encrypted_text)
    end

    def decrypt(ciphertext) do
        secret_key_hash = make_hash(@secret_key, 32)

        {:ok, ciphertext} = Base.decode64(ciphertext)
        <<iv::binary-16, ciphertext::binary>> = ciphertext
        decrypted_text = :crypto.crypto_one_time(:aes_256_cbc, secret_key_hash, iv, ciphertext, false)

        unpad_pkcs7(decrypted_text)
    end
    
    defp pad_pkcs7(message, blocksize) do
        pad = blocksize - rem(byte_size(message), blocksize)
        message <> to_string(List.duplicate(pad, pad))
    end

    defp unpad_pkcs7(data) do
        <<pad>> = binary_part(data, byte_size(data), -1)
        binary_part(data, 0, byte_size(data) - pad)
    end

    defp make_hash(text, length) do
      :crypto.hash(:sha512, text)
        |> Base.encode16
        |> String.downcase
        |> String.slice(0, length)
    end

end

- 要点-链接

代码语言:javascript
复制
<?php
    $ENCRYPTION_KEY = "put something secret here";
    $ENCRYPTION_ALGORITHM = 'AES-256-CBC';

    function encrypt($plain_text) {
        global $ENCRYPTION_KEY;
        global $ENCRYPTION_ALGORITHM;
        $EncryptionKey = make_hash($ENCRYPTION_KEY, 32);

        // create random Initialization Vector
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($ENCRYPTION_ALGORITHM));

        $encrypted_text = openssl_encrypt(
            $plain_text,
            $ENCRYPTION_ALGORITHM,
            $EncryptionKey,
            OPENSSL_RAW_DATA,
            $iv 
        );

        # concatenate the IV for decryption
        return  base64_encode($iv . $encrypted_text);
    }

    function decrypt($ciphertext) {
        global $ENCRYPTION_KEY;
        global $ENCRYPTION_ALGORITHM;
        $EncryptionKey = make_hash($ENCRYPTION_KEY, 32);

        $ciphertext = base64_decode($ciphertext);
        // get Initialization Vector part (16 bytes long)
        $iv = substr($ciphertext, 0, 16);
        // rest is actual cipher text
        $ciphertext = substr($ciphertext, 16);

        $decrypted_text = openssl_decrypt(
            $ciphertext,
            $ENCRYPTION_ALGORITHM,
            $EncryptionKey,
            OPENSSL_RAW_DATA,
            $iv
        );

        return $decrypted_text;
    }

    function make_hash($text, $length) {
        $hash_key = hash("sha512", $text, false);
        return substr($hash_key,0,$length);
    }

    // $ct = encrypt("code");
    // $dt = decrypt($ct);
    // echo $ct."\n";
    // echo $dt."\n";
?>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69187372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档