简体   繁体   English

Golang AES ECB 加密

[英]Golang AES ECB Encryption

Trying to emulate an algorithm in Go that is basically AES ECB Mode encryption.试图在 Go 中模拟一种基本上是 AES ECB 模式加密的算法。

Here's what I have so far这是我到目前为止所拥有的

func Decrypt(data []byte) []byte {
    cipher, err := aes.NewCipher([]byte(KEY))
    if err == nil {
        cipher.Decrypt(data, PKCS5Pad(data))
        return data
    }
    return nil
}

I also have a PKCS5Padding algorithm, which is tested and working, which pads the data first.我还有一个 PKCS5Padding 算法,该算法已经过测试和工作,它首先填充数据。 I cant find any information on how to switch the encryption mode in the Go AES package (it's definitely not in the docs ).我在 Go AES 包中找不到任何关于如何切换加密模式的信息(它绝对不在文档中)。

I have this code in another language, which is how I know this algorithm isn't working quite correctly.我有另一种语言的代码,这就是我知道这个算法工作不正常的原因。

EDIT: Here is the method as I have interpreted from on the issue page编辑:这是我在问题页面上解释的方法

func AESECB(ciphertext []byte) []byte {
    cipher, _ := aes.NewCipher([]byte(KEY))
    fmt.Println("AESing the data")
    bs := 16
    if len(ciphertext)%bs != 0     {
        panic("Need a multiple of the blocksize")
    }

    plaintext := make([]byte, len(ciphertext))
    for len(plaintext) > 0 {
        cipher.Decrypt(plaintext, ciphertext)
        plaintext = plaintext[bs:]
        ciphertext = ciphertext[bs:]
    }
    return plaintext
}

This is actually not returning any data, maybe I screwed something up when changing it from encripting to decripting这实际上并没有返回任何数据,也许我在将它从 encripting 更改为 decripting 时搞砸了一些事情

Electronic codebook ("ECB") is a very straightforward mode of operation. 电子码本(“ECB”)是一种非常直接的操作模式。 The data to be encrypted is divided into byte blocks, all having the same size.要加密的数据被分成大小相同的字节块。 For each block, a cipher is applied, in this case AES , generating the encrypted block.对于每个块,应用密码,在本例中为AES ,生成加密块。

The code snippet below decrypts AES-128 data in ECB (note that the block size is 16 bytes):下面的代码片段解密了 ECB 中的 AES-128 数据(注意块大小为 16 字节):

package main

import (
    "crypto/aes"
)

func DecryptAes128Ecb(data, key []byte) []byte {
    cipher, _ := aes.NewCipher([]byte(key))
    decrypted := make([]byte, len(data))
    size := 16

    for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
        cipher.Decrypt(decrypted[bs:be], data[bs:be])
    }

    return decrypted
}

As mentioned by @OneOfOne, ECB is insecure and very easy to detect, as repeated blocks will always encrypt to the same encrypted blocks.正如@OneOfOne 所提到的,ECB 是不安全的并且很容易被检测到,因为重复的块将始终加密为相同的加密块。 This Crypto SE answer gives a very good explanation why.这个Crypto SE 答案给出了一个很好的解释。

Why?为什么? We left ECB out intentionally: it's insecure, and if needed it's trivial to implement.我们有意将欧洲央行排除在外:它不安全,而且如果需要,实施起来很简单。

https://github.com/golang/go/issues/5597 https://github.com/golang/go/issues/5597

I used your code so I feel the need to show you how I fixed it.我使用了你的代码,所以我觉得有必要向你展示我是如何修复它的。

I am doing the cryptopals challenges for this problem in Go.我正在 Go 中针对这个问题进行密码学挑战

I'll walk you through the mistake since the code is mostly correct.我将引导您解决错误,因为代码大部分是正确的。

for len(plaintext) > 0 {
    cipher.Decrypt(plaintext, ciphertext)
    plaintext = plaintext[bs:]
    ciphertext = ciphertext[bs:]
}

The loop does decrypt the data but does not put it anywhere.循环确实解密了数据,但没有把它放在任何地方。 It simply shifts the two arrays along producing no output.它只是简单地移动两个数组,不产生任何输出。

i := 0
plaintext := make([]byte, len(ciphertext))
finalplaintext := make([]byte, len(ciphertext))
for len(ciphertext) > 0 {
    cipher.Decrypt(plaintext, ciphertext)
    ciphertext = ciphertext[bs:]
    decryptedBlock := plaintext[:bs]
    for index, element := range decryptedBlock {
        finalplaintext[(i*bs)+index] = element
    }
    i++
    plaintext = plaintext[bs:]
} 
return finalplaintext[:len(finalplaintext)-5]

What this new improvement does is store the decrypted data into a new []byte called finalplaintext.这项新改进的作用是将解密后的数据存储到一个名为 finalplaintext 的新 [] 字节中。 If you return that you get the data.如果您返回,您将获得数据。

It's important to do it this way since the Decrypt function only works one block size at a time.这样做很重要,因为 Decrypt 函数一次只能处理一个块大小。

I return a slice because I suspect it's padded.我返回一个切片,因为我怀疑它被填充了。 I am new to cryptography and Go so anyone feel free to correct/revise this.我是密码学和 Go 的新手,所以任何人都可以随意更正/修改它。

Ideally you want to implement the crypto/cipher#BlockMode interface.理想情况下,您希望实现crypto/cipher#BlockMode接口。 Since an official one doesnt exist, I used crypto/cipher#NewCBCEncrypter as a starting point:由于官方不存在,我使用crypto/cipher#NewCB​​CEncrypter作为起点:

package ecb
import "crypto/cipher"

type ecbEncrypter struct { cipher.Block }

func newECBEncrypter(b cipher.Block) cipher.BlockMode {
   return ecbEncrypter{b}
}

func (x ecbEncrypter) BlockSize() int {
   return x.Block.BlockSize()
}

func (x ecbEncrypter) CryptBlocks(dst, src []byte) {
   size := x.BlockSize()
   if len(src) % size != 0 {
      panic("crypto/cipher: input not full blocks")
   }
   if len(dst) < len(src) {
      panic("crypto/cipher: output smaller than input")
   }
   for len(src) > 0 {
      x.Encrypt(dst, src)
      src, dst = src[size:], dst[size:]
   }
}

I was confused by a couple of things.我被一些事情弄糊涂了。

First i needed a aes-256 version of the above algorithm, but apparently the aes.Blocksize (which is 16) won't change when the given key has length 32. So it is enough to give a key of length 32 to make the algorithm aes-256首先,我需要上述算法的 aes-256 版本,但显然当给定的密钥长度为 32 时,aes.Blocksize(即 16)不会改变。因此,给出长度为 32 的密​​钥就足够了算法 aes-256

Second, the decrypted value still contains padding and the padding value changes depending on the length of the encrypted string.其次,解密后的值仍然包含填充,填充值根据加密字符串的长度而变化。 Eg when there are 5 padding characters the padding character itself will be 5.例如,当有 5 个填充字符时,填充字符本身将为 5。

Here is my function which returns a string:这是我的函数,它返回一个字符串:

func DecryptAes256Ecb(hexString string, key string) string {
  data, _ := hex.DecodeString(hexString)

  cipher, _ := aes.NewCipher([]byte(key))

  decrypted := make([]byte, len(data))
  size := 16

  for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
    cipher.Decrypt(decrypted[bs:be], data[bs:be])
  }

  // remove the padding. The last character in the byte array is the number of padding chars
  paddingSize := int(decrypted[len(decrypted)-1])
  return string(decrypted[0 : len(decrypted)-paddingSize])
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM