drcvvkx914772 2016-03-31 14:42
浏览 317
已采纳

使用Go和PHP进行AES加密

I am using AES encryption in Go and PHP. But both the languages does not encrypt/decrypt each other ciphertext. Following i have tried in php

       class Crypto {
    private $encryptKey = "keyforencryption";
    private $iv = 'ivusedforencrypt';
    private $blocksize = 16;
    public function encrypt($toEncrypt){
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
        //$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        return base64_encode($this->iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CFB, $this->iv));
    }

    public function decrypt($toDecrypt){
       $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);//$this->blocksize;
       $toDecrypt = base64_decode($toDecrypt);
       return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CFB, substr($toDecrypt, 0, $iv_size)));
    }

}

$c = new Crypto();
echo "Encrypted : ".$e =  $c->encrypt("test");
echo "<br/>Decrypted : ".$c->decrypt($e);

output : aXZ1c2VkZm9yZW5jcnlwdDpdZEinU2rB

and this one in Go with AES

    package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "errors"
    "fmt"
    "io"
    "log"
)

func main() {
    key := []byte("keyforencryption")
    plaintext := []byte("test")
    fmt.Printf("%s
", plaintext)
    ciphertext, err := encrypt(key, plaintext)
    if err != nil {
        log.Fatal(err)
    }
    b := base64.StdEncoding.EncodeToString(ciphertext)
    fmt.Printf("Encrypted text : %s
", b)
    result, err := decrypt(key, b)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Decrypted Text : %s
", result)
}

func encrypt(key, text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    //b := base64.StdEncoding.EncodeToString(text)
    ciphertext := make([]byte, aes.BlockSize+len(text))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, err
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text))
    return ciphertext, nil
}

func decrypt(key []byte, text1 string) ([]byte, error) {
    text, _ := base64.StdEncoding.DecodeString(string(text1))
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    if len(text) < aes.BlockSize {
        return nil, errors.New("ciphertext too short")
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    b := base64.StdEncoding.EncodeToString(text)
    data, err := base64.StdEncoding.DecodeString(string(b))
    if err != nil {
        return nil, err
    }
    return data, nil
}

output : ZVnhCXjIvtGKBdqvjwHRZKcVy34=

any help would be appreciable.

  • 写回答

2条回答 默认 最新

  • dongshuo2752 2016-04-02 06:32
    关注

    CFB mode has an issue, this will work in CBC mode

    class Crypto {
        private $encryptKey = "keyforencryption";
        public function encrypt($toEncrypt){
            $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
            $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
            return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CBC, $iv));
        }
    
        public function decrypt($toDecrypt){
           $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
           echo "<br/>".$toDecrypt = base64_decode($toDecrypt);
           return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
        }
    }
    
    $c = new Crypto();
    echo "Encrypted : ".$e =  $c->encrypt("test123");
    echo "<br/>Decrypted : ".$c->decrypt($e);
    

    and this one in golang

    package main
    
    import (
        "crypto/aes"
        "crypto/cipher"
        "crypto/rand"
        "encoding/base64"
        "fmt"
        "io"
        "bytes"
    )
    
    func main() {
        e:= cbcEncrypt()
        fmt.Printf("Encrypted String : %s
    ", e)
    
        d:= cbcDecrypt(e)
        fmt.Printf("Decrypted String : %s
    ", d)
    }
    
    func cbcDecrypt(text1 string) []byte{
        key := []byte("keyforencryption")
        ciphertext, _ := base64.StdEncoding.DecodeString(string(text1))
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
    
        // include it at the beginning of the ciphertext.
        if len(ciphertext) < aes.BlockSize {
            panic("ciphertext too short")
        }
        iv := ciphertext[:aes.BlockSize]
        ciphertext = ciphertext[aes.BlockSize:]
    
        // CBC mode always works in whole blocks.
        if len(ciphertext)%aes.BlockSize != 0 {
            panic("ciphertext is not a multiple of the block size")
        }
    
        mode := cipher.NewCBCDecrypter(block, iv)
    
        // CryptBlocks can work in-place if the two arguments are the same.
        mode.CryptBlocks(ciphertext, ciphertext)
        ciphertext = PKCS5UnPadding(ciphertext)
        return ciphertext
    }
    
    func cbcEncrypt() string{
        key := []byte("keyforencryption")
        plaintext := []byte("testssssss")
        plaintext = PKCS5Padding(plaintext, 16)
        // CBC mode works on blocks so plaintexts may need to be padded to the
        // next whole block. For an example of such padding, see
        // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
        // assume that the plaintext is already of the correct length.
        if len(plaintext)%aes.BlockSize != 0 {
            panic("plaintext is not a multiple of the block size")
        }
    
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
    
        // The IV needs to be unique, but not secure. Therefore it's common to
        // include it at the beginning of the ciphertext.
        ciphertext := make([]byte, aes.BlockSize+len(plaintext))
        iv := ciphertext[:aes.BlockSize]
        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
            panic(err)
        }
    
        mode := cipher.NewCBCEncrypter(block, iv)
        mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
    
        // It's important to remember that ciphertexts must be authenticated
        // (i.e. by using crypto/hmac) as well as being encrypted in order to
        // be secure.
    
        return base64.StdEncoding.EncodeToString(ciphertext)
    }
    
    func PKCS5Padding(src []byte, blockSize int) []byte {
        padding := blockSize - len(src)%blockSize
        padtext := bytes.Repeat([]byte{byte(padding)}, padding)
        return append(src, padtext...)
    }
    
    func PKCS5UnPadding(src []byte) []byte {
        length := len(src)
        unpadding := int(src[length-1])
        return src[:(length - unpadding)]
    }
    

    this should work

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?
  • ¥15 Arcgis相交分析无法绘制一个或多个图形
  • ¥15 关于#r语言#的问题:差异分析前数据准备,报错Error in data[, sampleName1] : subscript out of bounds请问怎么解决呀以下是全部代码:
  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)