Home > Blockchain >  (Go) Encrypting / decrypting string results in lost characters
(Go) Encrypting / decrypting string results in lost characters

Time:11-13

I am attempting to encrypt sensitive data before storing it. First, I generate a key to be used for the encryption process:

import (
    "crypto/aes"
    CR "crypto/rand"
    "encoding/hex"
    "errors"
    "log"
    "os"
)

// []byte key used to encrypt tokens before saving to local file system
var key = make([]byte, 32)

func createKey(key *[]byte) {
    _, err = CR.Read(*key)
    if err != nil {
        log.Println("Error creating key from crypto/rand package:", err)
    }
}

Next I create functions that encrypt and decrypt a string respectively:

func encryptToken(t token) string {
    original := t.ID // ID is string member of token

    cipher, err := aes.NewCipher(key)
    if err != nil {
        log.Println("Error creating cipher during encrypt:", err)
    }

    out := make([]byte, len(original))
    cipher.Encrypt(out, []byte(original))

    return hex.EncodeToString(out) // this will be written to a csv file 

    // appears in file as: cec35df876e1b77diefg9023366c5f2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
}

func decryptToken(s string) string {
    ciphertext, err := hex.DecodeString(s) // s is read from csv file
    if err != nil {
        log.Println("Error decoding string from hex:", err)
    }

    cipher, err := aes.NewCipher(key)
    if err != nil {
        log.Println("Error creating cipher during decrypt:", err)
    }

    original := make([]byte, len(ciphertext))
    cipher.Decrypt(original, ciphertext)

    originalAsString := string(original[:])

    return originalAsString  // returns: 6f928e728f485403

    // original token was: 6f928e728f485403e254049f684ea5ec853adcfa9553cdfc956fr45671447c57
}

Considering that encryptToken() returns a hex string with so many zeros, I am certain this is where my problem is. I've experimented adjusting the length of key, but using a value other than 32 in var key = make([]byte, 32) will result in a panic involving invalid memory address or nil pointer dereference. Why is this?

CodePudding user response:

I am not familiar with the library, but it might just be doing one block of AES, AES is a 16 byte block cypher, which seems to be what you get back, one 16 byte block... to do a whole arbitrary chunk of AES, you have to pad it to a full size mod 16 = 0 bytes (look up PKCS5/7), then do one block... then, either CTR or CBC (the IV will come from either the position or the output of the last block), then the next block and so on... so I think you are using the AES block primitive rather than a whole blob sort of thing, (which in addition to a key requires a block mode and an iv)

CodePudding user response:

The shortest answer is probably: As @GradyPlayer suggested, you're using your cipher the wrong way. You have to hand it over to an encrypter instead which applies it to all the bytes. The pattern looks like that:

ciphertext = make([]byte, len(plaintext))
cbc := cipher.NewCBCEncrypter(cipher, iv)
cbc.CryptBlocks(ciphertext, plaintext)

That said, here you would still have to put the initialization vector in front of the ciphertext (that's a usual place to put it at least, and the decrypter might expect it to be located here), and you still have to think about padding (if you're using CBC as I did).

So while it's not directly addressing the question, I think it would help you do get more code for a better understanding. Here is a gist I've just created. Disclaimer: I mostly assembled code fragments from other places. So I merely put the pieces together you can see here, and gained some understanding on the road.

CodePudding user response:

The accepted answer, and especially the comment from Topaco, helped me arrive to this solution, I am posting here for anyone that may come across this:

var key = make([]byte, 32)
var nonce = make([]byte, 12)

func encryptToken(t token) string {
    original := t.ID // ID is string member of token

    block, err := aes.NewCipher(key)
    if err != nil {
        log.Println("Error creating cipher during encrypt:", err)
    }

    aesgcm, err := cipher.NewGCM(block)
    if err != nil {
        log.Println("Error creating GCM during encrypt:", err)
    }

    ciphertext := aesgcm.Seal(nil, nonce, []byte(original), nil)

    return hex.EncodeToString(ciphertext)
}

func decryptToken(s string) string {
    ciphertext, err := hex.DecodeString(s)
    if err != nil {
        log.Println("Error decoding string from hex:", err)
    }

    block, err := aes.NewCipher(key)
    if err != nil {
        log.Println("Error creating cipher during decrypt:", err)
    }

    aesgcm, err := cipher.NewGCM(block)
    if err != nil {
        log.Println("Error creating GCM during decrypt:", err)
    }

    original, err := aesgcm.Open(nil, nonce, ciphertext, nil)
    if err != nil {
        log.Println("Error decrypting to string:", err)
    }
    originalAsString := string(original)

    return originalAsString
}

Reference: https://pkg.go.dev/crypto/cipher#example-NewGCM-Encrypt

  • Related