Golang AES ECB Encryption

Electronic codebook ("ECB") is a very straightforward mode of operation. 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.

The code snippet below decrypts AES-128 data in ECB (note that the block size is 16 bytes):

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. This Crypto SE answer gives a very good explanation why.


Why? We left ECB out intentionally: it's insecure, and if needed it's trivial to implement.

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.

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. 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.

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.


Ideally you want to implement the crypto/cipher#BlockMode interface. Since an official one doesn't exist, I used crypto/cipher#NewCBCEncrypter as a starting point:

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:]
   }
}