GO - Golang AES128 ECB Decryption - go

I find the snippet of the code from https://stackoverflow.com/questions/24072026/golang-aes-ecb-encryption/71614065?noredirect=1#comment126568172_71614065in golang to 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
}
But I am unable to understand it. I tried to search full code online but I no luck.
Can someone provide the full code or explain it.
Sorry, I am new to golang
I tried to search online but was unable to get the full code and understand it.

First, keep in mind that ECB is insecure and must not be used for real encryption. That being said, here is what the code does line by line:
cipher, _ := aes.NewCipher([]byte(key))
This returns a new object which has methods to perform AES encryption/decryption, using the given key.
decrypted := make([]byte, len(data))
This allocates space to hold the decrypted result. The length is the same as the length of the input.
size := 16
This is the block size of the AES cipher in bytes. We could also have written size := cipher.BlockSize() here. The length of the input must be a multiple of 16 bytes.
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size { ... }
This iterates over the 16 byte blocks in the input. The first block has start bs = 0 and end be = size, and the we just add 16 to both bs and be repeatedly to get all the other blocks.
cipher.Decrypt(decrypted[bs:be], data[bs:be])
This uses the cipher object we created at the start to decrypt a single block. The input is data[bs:be] and the output is stored in decrypted[bs:be]. After the loop is finished, the slice decrypted contains the decrypted cleartext.

Related

How do I encrypt special characters or numbers using AES-256?

I would like to encrypt a string in Go using AES-256, without any GCM processing, to compare against MQL4. I encounter issues when I try to encrypt special characters or numbers. Should I be pre-processing my plaintext somehow? I am new to Go so any help would be appreciated; my code is below this explanation.
If I encrypt the plaintext "This is a secret" and then decrypt the ciphertext (encoded to hex), I get the same result (i.e. "This is a secret"). pt is the variable name of the plaintext in the code below.
If I try to encrypt "This is a secret; 1234", the ciphertext has a group of zeroes at the end, and when I decrypt I only get "This is a secret". Similar ciphertext in MQL4 does not have zeroes at the end and decrypts correctly.
If I try to encrypt only "1234", I get build errors, stemming from "crypto/aes.(*aesCipherAsm).Encrypt(0xc0000c43c0, 0xc0000ac058, 0x4, 0x4, 0xc0000ac070, 0x4, 0x8)
C:/Program Files/Go/src/crypto/aes/cipher_asm.go:60 +0x125"
Here is my code:
package main
import (
"crypto/aes"
"encoding/hex"
"fmt"
)
func main() {
// cipher key
key := "thisis32bitlongpassphraseimusing"
// plaintext
pt := "This is a secret"
// pt := "This is a secret; 1234" // zeroes in ciphertext
// pt := "1234" // doesn't build
c := EncryptAES([]byte(key), pt)
// plaintext
fmt.Println(pt)
// ciphertext
fmt.Println(c)
// decrypt
DecryptAES([]byte(key), c)
}
func EncryptAES(key []byte, plaintext string) string {
c, err := aes.NewCipher(key)
CheckError(err)
out := make([]byte, len(plaintext))
c.Encrypt(out, []byte(plaintext))
return hex.EncodeToString(out)
}
func DecryptAES(key []byte, ct string) {
ciphertext, _ := hex.DecodeString(ct)
c, err := aes.NewCipher(key)
CheckError(err)
pt := make([]byte, len(ciphertext))
c.Decrypt(pt, ciphertext)
s := string(pt[:])
fmt.Println("DECRYPTED:", s)
}
func CheckError(err error) {
if err != nil {
panic(err)
}
}
You're creating a raw AES encryptor here. AES can only encrypt precisely 16 bytes of plaintext, producing exactly 16 bytes of cipher text. Your first example "This is a secret" is exactly 16 bytes long, so it works as expected. Your second example is too long. Only the first 16 bytes are being encrypted. The third example is too short and you're likely running into uninitialized memory.
The specific characters in your text are irrelevant. Encryption is performed on raw bytes, not letters.
In order to encrypt larger (or smaller) blocks of text, you need to use a block cipher mode on top of AES. Common modes are GCM, CBC, and CTR, but there are many others. In most cases, when someone says "AES" without any qualifier, they mean AES-CBC. (GCM is becoming much more popular, and it's a great mode, but it's not so popular that it's assumed quite yet.)
I don't know anything about MQL4, but I assume you're trying to reimplement CryptEncode? I don't see any documentation on how they do the encryption. You need to know what mode they use, how they derive their key, how they generate (and possibly encode) their IV, whether they include an HMAC or other auth, and more. You need to know exactly how they implement whatever they mean by "CRYPT_AES256." There is no one, standard answer to this.
MQL4 only supports a very specific implementation of AES encryption and unless you use the correct settings in your other code you will not achieve compatibility between the two platforms.
Specifically you need to ensure the following are implemented:
Padding Mode: Zeros
Cipher Mode: ECB (so no IV)
KeySize: 256
BlockSize: 128
You also need to remember in MQL4 that encryption/decryption is a two stage process (to AES256 then to BASE64).
You can try the online AES encryption/decryption tool to verify your results available here: The online toolbox

How to fetch exponent and modulus in Little Endian format from a byte array of RSA public key

I have a requirement where I have a byte array in Little Endian format as input. I need to fetch exponent and modulus from it, create a public key and use it to encrypt data. Hence I put following piece of code:
exponentLen := 4
exponentArr := key[:exponentLen] - ///Where key is the input byte array
modulusStrOffset := exponentLen
n := big.Int{}
n.SetBytes(key[modulusStrOffset:])
eb := big.Int{}
eb.SetBytes(exponentArr)
ex, err := strconv.Atoi(eb.String())
if err != nil {
return nil, errors.Wrap(err, "GetRsaPubKey: Strconv to int")
}
pubKey := rsa.PublicKey{N: &n, E: int(ex)}
cipherText, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, swk, nil) /// swk is the data to be encrypted
This code successfully encrypts data without throwing any error.
However it fails on decryption side.
This is so because SetBytes() presumes that input byte array is in Big Endian format(our byte array is however in LE). So the modulus and exponent evaluated is wrong.
Is there a way to change byte order of input array from LE to BE and then create exponents and modulus in Little Endian format and then create public key and use it for encryption.. Please note I tried using:
var n1 big.Int
n1.SetBits(n.Bits())
but the problem persists.

Go Blowfish weird stuff

I have the following function which encodes the string using Blowfish.If I put just a string to byte array it works. The problem is with line
cipher.Encrypt(enc[0:],src)
func BlowFish(str string){
key := []byte("super secret key")
cipher,err := blowfish.NewCipher(key)
if err != nil {
log.Fatal(err)
}
//very weird that I get index out of range if I insert a var
src :=[]byte(str+"\n\n\n")
var enc [512]byte
cipher.Encrypt(enc[0:],src)
fmt.Println("Encoded",enc)
var decrypt[8] byte
cipher.Decrypt(decrypt[0:],enc[0:])
result:=bytes.NewBuffer(nil)
result.Write(decrypt[0:8])
fmt.Println(string(result.Bytes()))
}
I don't understand the problem
While this may result in an error using Go Blowfish, it is correct. Blowfish is a 64-bit (read 8-byte) block cipher. As you've discovered, not only does your string have to be 8 bytes with padding, but any data you wish to encrypt must be padded so that all blocks are equal to eight bytes.
To do so, you should be checking the modulus of your data, and padding the remainder so that the length of the data is a multiple of 8, like so.
func blowfishChecksizeAndPad(pt []byte) []byte {
// calculate modulus of plaintext to blowfish's cipher block size
// if result is not 0, then we need to pad
modulus := len(pt) % blowfish.BlockSize
if modulus != 0 {
// how many bytes do we need to pad to make pt to be a multiple of
//blowfish's block size?
padlen := blowfish.BlockSize - modulus
// let's add the required padding
for i := 0; i < padlen; i++ {
// add the pad, one at a time
pt = append(pt, 0)
}
}
// return the whole-multiple-of-blowfish.BlockSize-sized plaintext
// to the calling function
return pt
}
Looks like I found what's wrong. cypher.Encrypt accepts byte array of length 8. But the length of byte array []byte(str+"\n\n\n") is 4. That's why I get an index out of range. If I have an array []byte("My str to encode"+"\n\n\n"). It's len is len of 2 strings. The solution for now is to add more \n chars to have the length of array str+"\n....\n" >=than 8

ed25519.Public result is different

Using the package https://github.com/golang/crypto/tree/master/ed25519 i m trying to get a public key for a given private key.
Those data are from http://www.bittorrent.org/beps/bep_0044.html: test 2 (mutable with salt)
Problem is, ed25519.Public() won t return the same public key when i fed it with the given private key.
The golang implementation returns the last 32 bytes of the PVK. But in my test data this is unexpected.
The code here https://play.golang.org/p/UJNPCyuGQB
package main
import (
"encoding/hex"
"golang.org/x/crypto/ed25519"
"log"
)
func main() {
priv := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d"
pub := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548"
sig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"
// d := hex.EncodeToString([]byte(priv))
privb, _ := hex.DecodeString(priv)
pvk := ed25519.PrivateKey(privb)
buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")
sigb := ed25519.Sign(pvk, buffer)
pubb, _ := hex.DecodeString(pub)
sigb2, _ := hex.DecodeString(sig)
log.Println(ed25519.Verify(pubb, buffer, sigb))
log.Printf("%x\n", pvk.Public())
log.Printf("%x\n", sigb)
log.Printf("%x\n", sigb2)
}
How to generate the same public key than the bep using golang ?
This is due to different ed25519 private key formats. An ed25519 key starts out as a 32 byte seed. This seed is hashed with SHA512 to produce 64 bytes (a couple of bits are flipped too). The first 32 bytes of these are used to generate the public key (which is also 32 bytes), and the last 32 bytes are used in the generation of the signature.
The Golang private key format is the 32 byte seed concatenated with the 32 byte public key. The private keys in the Bittorrent document you are using are the 64 byte result of the hash (or possibly just 64 random bytes that are used the same way as the hash result).
Since it’s not possible to reverse the hash, you can’t convert the Bittorrent keys to a format that the Golang API will accept.
You can produce a version of the Golang lib based on the existing package.
The following code depends on the internal package golang.org/x/crypto/ed25519/internal/edwards25519, so if you want to use it you will need to copy that package out so that it is available to you code. It’s also very “rough and ready”, I’ve basically just copied the chunks of code needed from the existing code to get this to work.
Note that the public key and signature formats are the same, so as long as you are not sharing private keys you don’t need to use this code to get a working implementation. You will only need it if you want to check the test vectors.
First generating the public key from a private key:
// Generate the public key corresponding to the already hashed private
// key.
//
// This code is mostly copied from GenerateKey in the
// golang.org/x/crypto/ed25519 package, from after the SHA512
// calculation of the seed.
func getPublicKey(privateKey []byte) []byte {
var A edwards25519.ExtendedGroupElement
var hBytes [32]byte
copy(hBytes[:], privateKey)
edwards25519.GeScalarMultBase(&A, &hBytes)
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
return publicKeyBytes[:]
}
Next generating a signature:
// Calculate the signature from the (pre hashed) private key, public key
// and message.
//
// This code is mostly copied from the Sign function from
// golang.org/x/crypto/ed25519, from after the SHA512 calculation of the
// seed.
func sign(privateKey, publicKey, message []byte) []byte {
var privateKeyA [32]byte
copy(privateKeyA[:], privateKey) // we need this in an array later
var messageDigest, hramDigest [64]byte
h := sha512.New()
h.Write(privateKey[32:])
h.Write(message)
h.Sum(messageDigest[:0])
var messageDigestReduced [32]byte
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
var R edwards25519.ExtendedGroupElement
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
var encodedR [32]byte
R.ToBytes(&encodedR)
h.Reset()
h.Write(encodedR[:])
h.Write(publicKey)
h.Write(message)
h.Sum(hramDigest[:0])
var hramDigestReduced [32]byte
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
var s [32]byte
edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced)
signature := make([]byte, 64)
copy(signature[:], encodedR[:])
copy(signature[32:], s[:])
return signature
}
Finally we can use these two functions to demonstrate the test vectors:
privateKeyHex := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d"
expectedPublicKey := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548"
expectedSig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"
privateKey, _ := hex.DecodeString(privateKeyHex)
publicKey := getPublicKey(privateKey)
fmt.Printf("Calculated key: %x\n", publicKey)
fmt.Printf("Expected key: %s\n", expectedPublicKey)
keyMatches := expectedPublicKey == hex.EncodeToString(publicKey)
fmt.Printf("Public key matches expected: %v\n", keyMatches)
buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")
calculatedSig := sign(privateKey, publicKey, buffer)
fmt.Printf("Calculated sig: %x\n", calculatedSig)
fmt.Printf("Expected sig: %s\n", expectedSig)
sigMatches := expectedSig == hex.EncodeToString(calculatedSig)
fmt.Printf("Signature matches expected: %v\n", sigMatches)

Go AES CFB compatibility

I am developing a client-side app in Go that relies on AES CFB. The server-side is written in C. My problem is that Go's AES CFB implementation appears to differ from many others (including OpenSSL). I wrote this to test my theory:-
package main
import (
"fmt"
"encoding/hex"
"crypto/cipher"
"crypto/aes"
)
func encrypt_aes_cfb(plain, key, iv []byte) (encrypted []byte) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
encrypted = make([]byte, len(plain))
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(encrypted, plain)
return
}
func decrypt_aes_cfb(encrypted, key, iv []byte) (plain []byte) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
plain = make([]byte, len(encrypted))
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(plain, encrypted)
return
}
func main() {
plain := []byte("Hello world.....")
key := []byte("01234567890123456789012345678901")
iv := []byte("0123456789012345")
enc := encrypt_aes_cfb(plain, key, iv)
dec := decrypt_aes_cfb(enc, key, iv)
fmt.Println("Key: ", hex.EncodeToString(key))
fmt.Println("IV: ", hex.EncodeToString(iv))
fmt.Println("Enc: ", hex.EncodeToString(enc))
fmt.Println("In: ", hex.EncodeToString(plain))
fmt.Println("Out: ", hex.EncodeToString(dec))
}
When this is run, it appears to work perfectly, however, if the encrypted bytes are pasted into another AES implementation and decrypted using the same key and IV, the plaintext is corrupted (except for the first Byte). http://aes.online-domain-tools.com/ provides a simple means to test this. Any suggestions why this might be happening and how I can resolve it?
Thanks
Steve
(Firstly, an obligatory warning: CFB mode is a sign of homegrown crypto. Unless you're implementing OpenPGP you should be using an AE mode like AES-GCM or NaCl's secretbox. If you're forced to use CFB mode, I hope that you're authenticating ciphertexts with an HMAC at least.)
With that aside, CFB mode in Go is there for OpenPGP support. (OpenPGP uses both a tweaked CFB mode called OCFB, and standard CFB mode in different places.) The Go OpenPGP code appears to interoperate with other implementations at least.
Nick is correct that test vectors are missing in the Go crypto package. The testing was coming from the OpenPGP code, but packages should stand alone and so I'll add tests to crypto/cipher with the test vectors from section F.3.13 of [1].
My best guess for the source of any differences is that CFB is parameterised by a chunk size. This is generally a power of two number of bits up to the block size of the underlying cipher. If the chunk size isn't specified then it's generally taken to be the cipher block size, which is what the Go code does. See [1], section 6.3. A more friendly explanation is given by [2].
Small chunk sizes were used in the dark ages (the late 90s) when people worried about things like cipher resync in the face of ciphertext loss. If another implementation is using CFB1 or CFB8 then it'll be very different from Go's CFB mode and many others. (Go's code does not support smaller chunk sizes.)
[1] http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
[2] http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
I investigated this with the following inputs because I was unsure of the bit/byte order for both inputs and outputs :
Key: 00000000000000000000000000000000
IV: 00000000000000000000000000000000
Enc: 66
In: 00
Out: 00
http://play.golang.org/p/wl2y1EE6lK
Which matches the tool you provided, and then this :
Key: 00000000000000000000000000000000
IV: 00000000000000000000000000000000
Enc: 66e94b
In: 000000
Out: 000000
http://play.golang.org/p/DNC42m2oU5
Which doesn't match the tool :
6616f9
http://aes.online-domain-tools.com/link/63687gDNzymApefh/
The first byte matches, which indicates there may be a feedback issue.
So I checked the Go package's code and I think there is a bug here :
func (x *cfb) XORKeyStream(dst, src []byte) {
for len(src) > 0 {
if x.outUsed == len(x.out) {
x.b.Encrypt(x.out, x.next)
x.outUsed = 0
}
if x.decrypt {
// We can precompute a larger segment of the
// keystream on decryption. This will allow
// larger batches for xor, and we should be
// able to match CTR/OFB performance.
copy(x.next[x.outUsed:], src)
}
n := xorBytes(dst, src, x.out[x.outUsed:])
if !x.decrypt {
copy(x.next[x.outUsed:], dst) // BUG? `dst` should be `src`
}
dst = dst[n:]
src = src[n:]
x.outUsed += n
}
}
EDIT
After a second look at CFB mode it seems that Go's code is fine, so yeah it may be the other implementations are wrong.

Resources