使用Go和PHP进行AES加密

huangapple go评论115阅读模式
英文:

AES encryption with Go and PHP

问题

我正在使用Go和PHP进行AES加密。但是这两种语言无法互相加密/解密对方的密文。以下是我在PHP中尝试的代码:

  1. class Crypto {
  2. private $encryptKey = "keyforencryption";
  3. private $iv = 'ivusedforencrypt';
  4. private $blocksize = 16;
  5. public function encrypt($toEncrypt){
  6. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
  7. //$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  8. return base64_encode($this->iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CFB, $this->iv));
  9. }
  10. public function decrypt($toDecrypt){
  11. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);//$this->blocksize;
  12. $toDecrypt = base64_decode($toDecrypt);
  13. return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CFB, substr($toDecrypt, 0, $iv_size)));
  14. }
  15. }
  16. $c = new Crypto();
  17. echo "Encrypted : ".$e = $c->encrypt("test");
  18. echo "<br/>Decrypted : ".$c->decrypt($e);

输出结果为:aXZ1c2VkZm9yZW5jcnlwdDpdZEinU2rB

以下是使用AES在Go中的代码:

  1. package main
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "log"
  11. )
  12. func main() {
  13. key := []byte("keyforencryption")
  14. plaintext := []byte("test")
  15. fmt.Printf("%s\n", plaintext)
  16. ciphertext, err := encrypt(key, plaintext)
  17. if err != nil {
  18. log.Fatal(err)
  19. }
  20. b := base64.StdEncoding.EncodeToString(ciphertext)
  21. fmt.Printf("Encrypted text : %s\n", b)
  22. result, err := decrypt(key, b)
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. fmt.Printf("Decrypted Text : %s\n", result)
  27. }
  28. func encrypt(key, text []byte) ([]byte, error) {
  29. block, err := aes.NewCipher(key)
  30. if err != nil {
  31. return nil, err
  32. }
  33. //b := base64.StdEncoding.EncodeToString(text)
  34. ciphertext := make([]byte, aes.BlockSize+len(text))
  35. iv := ciphertext[:aes.BlockSize]
  36. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  37. return nil, err
  38. }
  39. cfb := cipher.NewCFBEncrypter(block, iv)
  40. cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text))
  41. return ciphertext, nil
  42. }
  43. func decrypt(key []byte, text1 string) ([]byte, error) {
  44. text, _ := base64.StdEncoding.DecodeString(string(text1))
  45. block, err := aes.NewCipher(key)
  46. if err != nil {
  47. return nil, err
  48. }
  49. if len(text) < aes.BlockSize {
  50. return nil, errors.New("ciphertext too short")
  51. }
  52. iv := text[:aes.BlockSize]
  53. text = text[aes.BlockSize:]
  54. cfb := cipher.NewCFBDecrypter(block, iv)
  55. cfb.XORKeyStream(text, text)
  56. b := base64.StdEncoding.EncodeToString(text)
  57. data, err := base64.StdEncoding.DecodeString(string(b))
  58. if err != nil {
  59. return nil, err
  60. }
  61. return data, nil
  62. }

输出结果为:ZVnhCXjIvtGKBdqvjwHRZKcVy34=

希望对你有所帮助。

英文:

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

  1. class Crypto {
  2. private $encryptKey = &quot;keyforencryption&quot;;
  3. private $iv = &#39;ivusedforencrypt&#39;;
  4. private $blocksize = 16;
  5. public function encrypt($toEncrypt){
  6. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
  7. //$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  8. return base64_encode($this-&gt;iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this-&gt;encryptKey, $toEncrypt, MCRYPT_MODE_CFB, $this-&gt;iv));
  9. }
  10. public function decrypt($toDecrypt){
  11. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);//$this-&gt;blocksize;
  12. $toDecrypt = base64_decode($toDecrypt);
  13. return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this-&gt;encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CFB, substr($toDecrypt, 0, $iv_size)));
  14. }
  15. }
  16. $c = new Crypto();
  17. echo &quot;Encrypted : &quot;.$e = $c-&gt;encrypt(&quot;test&quot;);
  18. echo &quot;&lt;br/&gt;Decrypted : &quot;.$c-&gt;decrypt($e);

output : aXZ1c2VkZm9yZW5jcnlwdDpdZEinU2rB

and this one in Go with AES

  1. package main
  2. import (
  3. &quot;crypto/aes&quot;
  4. &quot;crypto/cipher&quot;
  5. &quot;crypto/rand&quot;
  6. &quot;encoding/base64&quot;
  7. &quot;errors&quot;
  8. &quot;fmt&quot;
  9. &quot;io&quot;
  10. &quot;log&quot;
  11. )
  12. func main() {
  13. key := []byte(&quot;keyforencryption&quot;)
  14. plaintext := []byte(&quot;test&quot;)
  15. fmt.Printf(&quot;%s\n&quot;, plaintext)
  16. ciphertext, err := encrypt(key, plaintext)
  17. if err != nil {
  18. log.Fatal(err)
  19. }
  20. b := base64.StdEncoding.EncodeToString(ciphertext)
  21. fmt.Printf(&quot;Encrypted text : %s\n&quot;, b)
  22. result, err := decrypt(key, b)
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. fmt.Printf(&quot;Decrypted Text : %s\n&quot;, result)
  27. }
  28. func encrypt(key, text []byte) ([]byte, error) {
  29. block, err := aes.NewCipher(key)
  30. if err != nil {
  31. return nil, err
  32. }
  33. //b := base64.StdEncoding.EncodeToString(text)
  34. ciphertext := make([]byte, aes.BlockSize+len(text))
  35. iv := ciphertext[:aes.BlockSize]
  36. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  37. return nil, err
  38. }
  39. cfb := cipher.NewCFBEncrypter(block, iv)
  40. cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text))
  41. return ciphertext, nil
  42. }
  43. func decrypt(key []byte, text1 string) ([]byte, error) {
  44. text, _ := base64.StdEncoding.DecodeString(string(text1))
  45. block, err := aes.NewCipher(key)
  46. if err != nil {
  47. return nil, err
  48. }
  49. if len(text) &lt; aes.BlockSize {
  50. return nil, errors.New(&quot;ciphertext too short&quot;)
  51. }
  52. iv := text[:aes.BlockSize]
  53. text = text[aes.BlockSize:]
  54. cfb := cipher.NewCFBDecrypter(block, iv)
  55. cfb.XORKeyStream(text, text)
  56. b := base64.StdEncoding.EncodeToString(text)
  57. data, err := base64.StdEncoding.DecodeString(string(b))
  58. if err != nil {
  59. return nil, err
  60. }
  61. return data, nil
  62. }

output : ZVnhCXjIvtGKBdqvjwHRZKcVy34=

any help would be appreciable.

答案1

得分: 4

CFB模式存在问题,在CBC模式下可以正常工作。

  1. class Crypto {
  2. private $encryptKey = "keyforencryption";
  3. public function encrypt($toEncrypt){
  4. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  5. $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  6. return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, $toEncrypt, MCRYPT_MODE_CBC, $iv));
  7. }
  8. public function decrypt($toDecrypt){
  9. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  10. echo "<br/>".$toDecrypt = base64_decode($toDecrypt);
  11. return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
  12. }
  13. }
  14. $c = new Crypto();
  15. echo "Encrypted : ".$e = $c->encrypt("test123");
  16. echo "<br/>Decrypted : ".$c->decrypt($e);
  1. package main
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "fmt"
  8. "io"
  9. "bytes"
  10. )
  11. func main() {
  12. e:= cbcEncrypt()
  13. fmt.Printf("Encrypted String : %s\n", e)
  14. d:= cbcDecrypt(e)
  15. fmt.Printf("Decrypted String : %s\n", d)
  16. }
  17. func cbcDecrypt(text1 string) []byte{
  18. key := []byte("keyforencryption")
  19. ciphertext, _ := base64.StdEncoding.DecodeString(string(text1))
  20. block, err := aes.NewCipher(key)
  21. if err != nil {
  22. panic(err)
  23. }
  24. // include it at the beginning of the ciphertext.
  25. if len(ciphertext) < aes.BlockSize {
  26. panic("ciphertext too short")
  27. }
  28. iv := ciphertext[:aes.BlockSize]
  29. ciphertext = ciphertext[aes.BlockSize:]
  30. // CBC mode always works in whole blocks.
  31. if len(ciphertext)%aes.BlockSize != 0 {
  32. panic("ciphertext is not a multiple of the block size")
  33. }
  34. mode := cipher.NewCBCDecrypter(block, iv)
  35. // CryptBlocks can work in-place if the two arguments are the same.
  36. mode.CryptBlocks(ciphertext, ciphertext)
  37. ciphertext = PKCS5UnPadding(ciphertext)
  38. return ciphertext
  39. }
  40. func cbcEncrypt() string{
  41. key := []byte("keyforencryption")
  42. plaintext := []byte("testssssss")
  43. plaintext = PKCS5Padding(plaintext, 16)
  44. // CBC mode works on blocks so plaintexts may need to be padded to the
  45. // next whole block. For an example of such padding, see
  46. // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
  47. // assume that the plaintext is already of the correct length.
  48. if len(plaintext)%aes.BlockSize != 0 {
  49. panic("plaintext is not a multiple of the block size")
  50. }
  51. block, err := aes.NewCipher(key)
  52. if err != nil {
  53. panic(err)
  54. }
  55. // The IV needs to be unique, but not secure. Therefore it's common to
  56. // include it at the beginning of the ciphertext.
  57. ciphertext := make([]byte, aes.BlockSize+len(plaintext))
  58. iv := ciphertext[:aes.BlockSize]
  59. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  60. panic(err)
  61. }
  62. mode := cipher.NewCBCEncrypter(block, iv)
  63. mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  64. // It's important to remember that ciphertexts must be authenticated
  65. // (i.e. by using crypto/hmac) as well as being encrypted in order to
  66. // be secure.
  67. return base64.StdEncoding.EncodeToString(ciphertext)
  68. }
  69. func PKCS5Padding(src []byte, blockSize int) []byte {
  70. padding := blockSize - len(src)%blockSize
  71. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  72. return append(src, padtext...)
  73. }
  74. func PKCS5UnPadding(src []byte) []byte {
  75. length := len(src)
  76. unpadding := int(src[length-1])
  77. return src[:(length - unpadding)]
  78. }

这样应该可以工作。

英文:

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

  1. class Crypto {
  2. private $encryptKey = &quot;keyforencryption&quot;;
  3. public function encrypt($toEncrypt){
  4. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  5. $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  6. return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this-&gt;encryptKey, $toEncrypt, MCRYPT_MODE_CBC, $iv));
  7. }
  8. public function decrypt($toDecrypt){
  9. $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  10. echo &quot;&lt;br/&gt;&quot;.$toDecrypt = base64_decode($toDecrypt);
  11. return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this-&gt;encryptKey, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
  12. }
  13. }
  14. $c = new Crypto();
  15. echo &quot;Encrypted : &quot;.$e = $c-&gt;encrypt(&quot;test123&quot;);
  16. echo &quot;&lt;br/&gt;Decrypted : &quot;.$c-&gt;decrypt($e);

and this one in golang

  1. package main
  2. import (
  3. &quot;crypto/aes&quot;
  4. &quot;crypto/cipher&quot;
  5. &quot;crypto/rand&quot;
  6. &quot;encoding/base64&quot;
  7. &quot;fmt&quot;
  8. &quot;io&quot;
  9. &quot;bytes&quot;
  10. )
  11. func main() {
  12. e:= cbcEncrypt()
  13. fmt.Printf(&quot;Encrypted String : %s\n&quot;, e)
  14. d:= cbcDecrypt(e)
  15. fmt.Printf(&quot;Decrypted String : %s\n&quot;, d)
  16. }
  17. func cbcDecrypt(text1 string) []byte{
  18. key := []byte(&quot;keyforencryption&quot;)
  19. ciphertext, _ := base64.StdEncoding.DecodeString(string(text1))
  20. block, err := aes.NewCipher(key)
  21. if err != nil {
  22. panic(err)
  23. }
  24. // include it at the beginning of the ciphertext.
  25. if len(ciphertext) &lt; aes.BlockSize {
  26. panic(&quot;ciphertext too short&quot;)
  27. }
  28. iv := ciphertext[:aes.BlockSize]
  29. ciphertext = ciphertext[aes.BlockSize:]
  30. // CBC mode always works in whole blocks.
  31. if len(ciphertext)%aes.BlockSize != 0 {
  32. panic(&quot;ciphertext is not a multiple of the block size&quot;)
  33. }
  34. mode := cipher.NewCBCDecrypter(block, iv)
  35. // CryptBlocks can work in-place if the two arguments are the same.
  36. mode.CryptBlocks(ciphertext, ciphertext)
  37. ciphertext = PKCS5UnPadding(ciphertext)
  38. return ciphertext
  39. }
  40. func cbcEncrypt() string{
  41. key := []byte(&quot;keyforencryption&quot;)
  42. plaintext := []byte(&quot;testssssss&quot;)
  43. plaintext = PKCS5Padding(plaintext, 16)
  44. // CBC mode works on blocks so plaintexts may need to be padded to the
  45. // next whole block. For an example of such padding, see
  46. // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we&#39;ll
  47. // assume that the plaintext is already of the correct length.
  48. if len(plaintext)%aes.BlockSize != 0 {
  49. panic(&quot;plaintext is not a multiple of the block size&quot;)
  50. }
  51. block, err := aes.NewCipher(key)
  52. if err != nil {
  53. panic(err)
  54. }
  55. // The IV needs to be unique, but not secure. Therefore it&#39;s common to
  56. // include it at the beginning of the ciphertext.
  57. ciphertext := make([]byte, aes.BlockSize+len(plaintext))
  58. iv := ciphertext[:aes.BlockSize]
  59. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  60. panic(err)
  61. }
  62. mode := cipher.NewCBCEncrypter(block, iv)
  63. mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  64. // It&#39;s important to remember that ciphertexts must be authenticated
  65. // (i.e. by using crypto/hmac) as well as being encrypted in order to
  66. // be secure.
  67. return base64.StdEncoding.EncodeToString(ciphertext)
  68. }
  69. func PKCS5Padding(src []byte, blockSize int) []byte {
  70. padding := blockSize - len(src)%blockSize
  71. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  72. return append(src, padtext...)
  73. }
  74. func PKCS5UnPadding(src []byte) []byte {
  75. length := len(src)
  76. unpadding := int(src[length-1])
  77. return src[:(length - unpadding)]
  78. }

this should work

答案2

得分: 1

在PHP中,编码时使用填充(padding),解码时使用去填充(unpadding)。

以下是用于填充的函数:

  1. function pkcs5_pad($text)
  2. {
  3. $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  4. $pad = $blocksize - (strlen($text) % $blocksize);
  5. return $text . str_repeat(chr($pad), $pad);
  6. }

以下是用于去填充的函数:

  1. function pkcs5_unpad($text)
  2. {
  3. $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  4. $pad = ord($text[($len = strlen($text)) - 1]);
  5. $len = strlen($text);
  6. $pad = ord($text[$len-1]);
  7. return substr($text, 0, strlen($text) - $pad);
  8. }

这些函数使用了MCrypt扩展中的mcrypt_get_block_size函数来获取加密算法的块大小,并根据块大小进行填充或去填充操作。

英文:

Also use padding for encoding and unpadding for decode in php.

  1. function pkcs5_pad($text)
  2. {
  3. $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  4. $pad = $blocksize - (strlen($text) % $blocksize);
  5. return $text . str_repeat(chr($pad), $pad);
  6. }
  7. function pkcs5_unpad($text)
  8. {
  9. $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  10. $pad = ord($text[($len = strlen($text)) - 1]);
  11. $len = strlen($text);
  12. $pad = ord($text[$len-1]);
  13. return substr($text, 0, strlen($text) - $pad);
  14. }

huangapple
  • 本文由 发表于 2016年3月31日 22:42:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/36336629.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定