Golang AES ECB Encryption

13,043

Solution 1

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.

Solution 2

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

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

Solution 3

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.

Solution 4

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:]
   }
}
Share:
13,043
Jameo
Author by

Jameo

Email: [email protected] Blog: http://blog.mindblowninnovation.com Java, Objective-C, Javascript, HTML5, CSS3 programmer. Loves anything mobile/mobile web related.

Updated on June 21, 2022

Comments

  • Jameo
    Jameo almost 2 years

    Trying to emulate an algorithm in Go that is basically AES ECB Mode encryption.

    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. I cant find any information on how to switch the encryption mode in the Go AES package (it's definitely not in the docs).

    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

  • Kluyg
    Kluyg almost 10 years
    good point, also if you follow the link, you will find the simple ECB mode implementation in Go
  • elithrar
    elithrar almost 10 years
    But, of course, you wouldn't put that "simple ECB mode implementation" into any software (ever) because of its significant flaws, right? :)
  • Jameo
    Jameo almost 10 years
    @elithrar definitely not for new software...this is a requirement for an existing API that I am trying to interact with
  • zaph
    zaph over 6 years
    1. AES has one block size of 16-bytes, it is not related to the key size. AES has three key sizes of 128, 192 & 256 bits. 2. The padding seen here is PKCS#7, padding is necessary if the data to be encrypted is not always a multiple of the block size. 3. Most AES implementations (the aes Go implementations does not) will handle input data longer than one block and automatically handle the block calls and padding. 4. Instead see crypto/cipher which does handle blocking and padding.
  • Jarvis Johnson
    Jarvis Johnson about 5 years
    Thanks for this, was helpful. Worth noting this isn't restricted to 128-bit encryption - it will also work for 256-bit by passing in a 32 byte key instead of a 16 byte key.