How to handle invalid keys in NewCBCDecrypter example? - go

I found an example for the usage of CBC decrypter:
https://golang.org/pkg/crypto/cipher/#NewCBCDecrypter
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func main() {
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
fmt.Printf("%s\n", ciphertext)
}
It works fine. But if I modify the key to make it invalid then it returns some strange characters instead of throwing an error.
How could I make it more programmer friendly by throwing an error if the key is invalid?

How could I make it more programmer friendly by throwing an error if the key is invalid?
You cannot. That simply isn't how this stuff works. You supply a key and this key is used to decipher the input. There is no "correct" or "wrong" key here, there is just a key here.
You might be able to inspect the deciphered output: If you know the output always starts with some magic prefix or is a well-formed XML or anything you can check reliably after deciphering you can fail. But there is really nothing intrinsic to a key being wrong or right.

Related

Golang- AES Decryption is not returning same Text

I am following this documentation and was trying to implement a simple AES encryption and decryption with using GoLang. For plain text it is working fine however, for UUID it is not working. Excepting a resolution of this and why this is happening. Here is my sample code
package main
import (
"crypto/aes"
"encoding/hex"
"fmt"
)
func main() {
key := "thisis32bitlongpassphraseimusing"
pt := "a30a1777-e9f4-ed45-4755-add00172ebae"
c := EncryptAES([]byte(key), pt)
fmt.Println(pt)
fmt.Println(c)
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)
}
}
And here is the output
a30a1777-e9f4-ed45-4755-add00172ebae
e0f32a5bcf576754da4206cc967157ae0000000000000000000000000000000000000000
DECRYPTED: a30a1777-e9f4-ed
As you can see in the remaining last part of the UUID is disappearing. I have attached as a snap which says it didn't decrypt the last part properly. Does anyone know reasoning behind this? I have seen a close question like that but not and exactly one.
If you look at the page for the AES block cipher you'll find out that aes.NewCipher returns a Block as mentioned by Jake in the comments.
Now if you go to that page you'll see that this page points out various modes that you can use to create a real, secure cipher out of a block cipher. A block cipher only handles blocks of data, which are always 128 bits / 16 bytes in the case of AES. So this is precisely why there are all those zero's after the ciphertext, it encrypted 16 bytes and that was that. Note that ciphertext should always look as randomized bytes.
Unfortunately it doesn't directly list the authenticated (AEAD) modes, so please take a look here as well. That said, you can see that CTR mode is in there including examples, and that's the main idea missing from the question + my answer that you've linked to. Nothing in your code shows a mode of operation, and certainly not counter mode.
The problem with your code is that AES encryption requires the input to be a multiple of the block size (16 bytes for AES-128), but the UUID you're trying to encrypt ("a30a1777-e9f4-ed45-4755-add00172ebae")is 36 bytes long and it is causing the cipher to error.
One way to fix this issue is by padding the plaintext so that its length is a multiple of the block size before encryption. The Go standard library has a package called crypto/padding that provides functions for adding padding to plaintext.
You can modify your EncryptAES function like this:
func EncryptAES(key []byte, plaintext string) string {
c, err := aes.NewCipher(key)
CheckError(err)
plaintextBytes := []byte(plaintext)
// Add padding to plaintext
blockSize := c.BlockSize()
padding := blockSize - (len(plaintextBytes) % blockSize)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
plaintextBytes = append(plaintextBytes, padtext...)
out := make([]byte, len(plaintextBytes))
c.Encrypt(out, plaintextBytes)
return hex.EncodeToString(out)
}
Then in the DecryptAES function, you can remove the padding before decrypting the ciphertext like this:
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)
//Remove padding
padLen := int(pt[len(pt)-1])
s := string(pt[:len(pt)-padLen])
fmt.Println("DECRYPTED:", s)
}
As for padding schemes, you might want to try padding scheme like pkcs#5 or pkcs#7.

Deterministic RSA encryption in Golang - how to get same result for a given message under mutiple times of encryption

For the codes below of RSA encryption, every time when I do the encryption for the same message, the result would be different. I found that this is due to the rand.Reader in the rsa.EncryptOAEP function to make it more secure according to the doc. But I want the same result for the same message every time when I do the RSA encryption. How to do so using Golang? There is a similar question but it seems that answers are not about how to achieve this. Thank you!
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"fmt"
)
func main() {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
publicKey := privateKey.PublicKey
message := "super secret message"
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
&publicKey,
[]byte(message),
nil)
if err != nil {
panic(err)
}
fmt.Println("encrypted bytes: ", encryptedBytes)
}
Update: I want to do deterministic RSA because I want deterministic encryption results when using Hyperledger Fabric chaincode (blockchain smart contract) which requires deterministic outputs. Thank you all for the warnings. Then I guess I should focus on how to enable these encryption algorithms in chaincode. Relevant question for later comers' information if it helps :)
This approach, as you've read, breaks very important security features of the algorithm, and must never be used to secure live systems of any kind. However, for the purposes of certain kinds of testing and development, it can be useful. I will assume that this is what you mean to do with it.
The key is that rsa.EncryptOAEP accepts an arbitrary io.Reader for its entropy. It does not require this to be a rand.Reader. If you do not care about the security of the system, it can be whatever you like. For example, you could build a "zero reader" that just returns zeros forever:
type zeroReader struct{}
func (z zeroReader) Read(p []byte) (n int, err error) {
for i, _ := range p {
p[i] = 0
}
n = len(p)
return
}
With that, you can pass zeroReader{} as your entropy:
// !!! The security of this call is completely broken !!!
// !!! It must never be used on live data !!!
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
zeroReader{}, // !!! I am intentionally breaking the security here !!!
&publicKey,
[]byte(message),
nil)
If you do mean to use this for any kind of live data, then you must redesign your system to not require this. As in the case of the question you link, often people try to do this because they misunderstand RSA. Don't do that.
Playground

How to automate two os.Stdin input using Bash

I need to automate the input of a code segment like bellow where the inputs of the ReadString are distinct.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
buf := bufio.NewReader(os.Stdin)
value, err := buf.ReadString('\n')
if err != nil {
fmt.Println(err)
} else {
fmt.Println(value)
}
buf = bufio.NewReader(os.Stdin)
value, err = buf.ReadString('\n')
if err != nil {
fmt.Println(err)
} else {
fmt.Println(value)
}
}
I have tried several formats like the bellow one following answers of this question, unfortunately, none worked.
>> echo "data1
data2" | go run main.go
output: data1
EOF
Here data1 and data2 and input of the separate ReadString methods. I don't have control over the source code. So, I can only try changing the bash input. How to resolve this issue?
This is happening because the second string does not end with a newline. Looking at the documentation for ReadString:
If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF).
So, even though error is non-nil, you have the data. The following change should work for this specific case:
buf = bufio.NewReader(os.Stdin)
value, err = buf.ReadString('\n')
if value!="" {
fmt.Println(value)
}
if err != nil {
fmt.Println(err)
}
In general, even if you get an error from ReadString, you may still have nonempty data returned from the function.

Go lang 3DES partially decrypted the encrypted string

While performing decryption using 3des the given encrypted text is not fully decrypted, not sure where it went wrong, help me complete the decryption error
The code is avaialbe at Go Playground for Insection and run
package main
import (
"crypto/des"
"encoding/hex"
"fmt"
)
func main() {
// Mimimum Key Size of Length 24
key := "mysecretPasswordkeySiz24"
plainText := "https://8gwifi.org"
ct := EncryptTripleDES([]byte(key),plainText)
fmt.Printf("Original Text: %s\n",plainText)
fmt.Printf("3DES Encrypted Text: %s\n", ct)
DecryptTripleDES([]byte(key),ct)
}
func EncryptTripleDES(key []byte, plaintext string) string {
c,err := des.NewTripleDESCipher(key)
if err != nil {
fmt.Errorf("NewTripleDESCipher(%d bytes) = %s", len(key), err)
panic(err)
}
out := make([]byte, len(plaintext))
c.Encrypt(out, []byte(plaintext))
return hex.EncodeToString(out)
}
func DecryptTripleDES(key []byte, ct string) {
ciphertext, _ := hex.DecodeString(ct)
c, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
fmt.Errorf("NewTripleDESCipher(%d bytes) = %s", len(key), err)
panic(err)
}
plain := make([]byte, len(ciphertext))
c.Decrypt(plain, ciphertext)
s := string(plain[:])
fmt.Printf("3DES Decrypyed Text: %s\n", s)
}
The output
Original Text: https://8gwifi.org
3DES Encrypted Text: a6e5215154bf86d000000000000000000000
3DES Decrypyed Text: https://
the given encrypted text is not fully decrypted
The encrypted text you gave is fully decrypted. The problem is not (yet) the decryption but your encryption. As documented des.NewTripleDESCipher returns a cipher.Block and cipher.Block.Encrypt encrypts as documented only the first block of the input data. Given that DES has a block size of 8 byte only the first 8 byte of the input data are encrypted, i.e. https://.
This means in order to encrypt all data you must encrypt all blocks. Similar you need to decrypt all blocks when decrypting - but cipher.Block.Decrypt also decrypts only a single block.
Apart from that DES is broken, so don't use it for something serious.

Go encryption differs from Ruby encryption using same key and iv

I have the following Ruby code:
require 'base64'
require 'openssl'
data = '503666666'
key = '4768c01c4f598828ef80d9982d95f888fb952c5b12189c002123e87f751e3e82'
nonce = '4eFi6Q3PX1478767\n'
nonce = Base64.decode64(nonce)
c = OpenSSL::Cipher.new('aes-256-gcm')
c.encrypt
c.key = key
c.iv = nonce
result = c.update(data) + c.final
tag = c.auth_tag
puts Base64.encode64(result + tag) # => J3AVfNG84bz2UuXcfre7LVjSbMpX9XBq6g==\n
that I'm trying to replicate in Golang.
Here's what I have so far:
package main
import (
"fmt"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
)
func main() {
data := []byte("503666666")
key, err := hex.DecodeString(`4768c01c4f598828ef80d9982d95f888fb952c5b12189c002123e87f751e3e82`)
if err != nil {
panic(err)
}
nonceB64 := "4eFi6Q3PX1478767\n"
nonce, err := base64.StdEncoding.DecodeString(nonceB64)
if err != nil {
panic(err)
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
ciphertext := aesgcm.Seal(nil, nonce, data, nil)
fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(ciphertext))
}
However the outcome from the Go version is:
+S52HGbLV1xp+GnF0v8VNOqc5J2GY2+SqA==
vs.
J3AVfNG84bz2UuXcfre7LVjSbMpX9XBq6g==\n
Why am I getting different results?
Thanks,
The AES 256 cipher requires a 32 byte key. The Ruby code is setting the key to a 64 byte string consisting of hexadecimal digits. OpenSSL is truncating the string to 32 bytes before use (change key to '4768c01c4f598828ef80d9982d95f888' in the Ruby code and you'll get the same output).
The Go code however is hex decoding the key before use, converting the 64 hexadecimal digits to the 32 bytes required for the key.
If you want to change the Go code so that it matches the Ruby result, then you'll need to truncate the key and remove the hex decoding step:
key := []byte("4768c01c4f598828ef80d9982d95f888")
However, I'd argue that the key handling in the Go version of the code is better. If you want to change the Ruby version to match the Go version, you can hex decode the key before use:
key = [key].pack('H*')

Resources