3

I've writing a client-side app in Go that needs to interact with a C program on the server-side. The client does an AES CFB encrypt and the server decrypts. Unfortunately the server-side has a bug with reusing an initialization vector. It tries to do 3 decrypt operations based on:-
key1, iv
key2, iv
key3, iv

Due to this issue the iv is actually modified between decrypt operations. My problem now is how to reproduce this behaviour on the client side using Go.

By inserting a Println into the encrypt function below, I can see the cfb struct which, I think, contains the modified IV for the next block but because it's a stream interface, I'm not sure how to extract it into a byte slice. Any suggestions?

Thanks

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)
  fmt.Println(stream)
  return
}

func main() {
  plain := []byte("Hello world...16Hello world...32")
  key := make([]byte, 32)
  iv := make([]byte, 16)
  enc := encrypt_aes_cfb(plain, key, iv)
  fmt.Println("Key: ", hex.EncodeToString(key))
  fmt.Println("IV:  ", hex.EncodeToString(iv))
  fmt.Println("Enc: ", hex.EncodeToString(enc))
}
Community
  • 1
  • 1
Steve Crook
  • 1,013
  • 2
  • 13
  • 22
  • 1
    can't fix the server code instead? – OneOfOne Aug 26 '14 at 20:08
  • Maybe, in time, the server side can be fixed but doing so will break backward compatibility. – Steve Crook Aug 26 '14 at 20:17
  • *"Due to this issue the iv is actually modified between decrypt operations. My problem now is how to reproduce this behaviour on the client side using Go"* - don't reproduce broken behavior. Fix the problem. Since you have a memory problem, its likely not deterministic across languages. – jww Aug 27 '14 at 05:46

1 Answers1

6

Going down the path you're hinting at is a bit ugly, and prone to break when the implementation changes.

You can get the IV from the stream by:

s := reflect.Indirect(reflect.ValueOf(stream))
lastIV := s.FieldByName("next").Bytes()

But, there's an easier way! Concatenate the plain text inputs, so that the stream for the second starts with the IV from the end of the first (and so on).

Playground Example

combined := append(plain, plain2...)
encCombined := encrypt_aes_cfb(combined, key, iv)

enc := encCombined[:len(plain)]
enc2 := encCombined[len(plain):]
JimB
  • 104,193
  • 13
  • 262
  • 255
  • Ah, thanks very much JimB. Not only did you provide me an answer, you made me realize I didn't need it. :) – Steve Crook Aug 26 '14 at 20:14
  • 1
    @SteveCrook The usual method of thanking on StackOverflow is by upvoting and of course accepting answers on questions you've asked. It seems you haven't accepted any answers yet. You can do so by hitting the V mark on the left hand side of the answer. – Maarten Bodewes Aug 26 '14 at 20:41