Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

affected/package: crypto #63127

Closed
pedroalbanese opened this issue Sep 20, 2023 · 5 comments
Closed

affected/package: crypto #63127

pedroalbanese opened this issue Sep 20, 2023 · 5 comments

Comments

@pedroalbanese
Copy link

pedroalbanese commented Sep 20, 2023

Greetings!

I'm facing problems with the crypto library, more precisely the output encoding which seems to differ from other tools. This is causing problems with the integration with TCL/TK as in the example below.

tiny_script3.tcl:

#!/usr/bin/tclsh

package require base64
package require sha256

set a "this is the plain text"
set key [sha2::sha256 $a]
set iv [string range [sha2::sha256 $key] 0 31]

# Encrypt the text
set enc_output [exec edgetk -crypt enc -key $key -iv $iv -mode ctr << $a]

# Encode the ciphertext in base64
set encoded_enc_output [base64::encode $enc_output]

puts "\nCiphertext: $encoded_enc_output\n\n"

# Decode the ciphertext from base64
set decoded_enc_output [base64::decode $encoded_enc_output]

# Decrypt the ciphertext
set dec_output [exec edgetk -crypt dec -key $key -iv $iv -mode ctr << $decoded_enc_output]

puts "Plaintext: $dec_output\n"

TCL

This error occurs with my EDGETk tool, but can be reproduced in smaller code.

Example in Go:

package main
import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"flag"
	"fmt"
	"crypto/sha256"
	"golang.org/x/crypto/pbkdf2"
	"io"
	"log"
	"os"
)

	var derive = flag.Bool("d", false, "Derive password-based key.")
	var iter = flag.Int("i", 1024, "Iterations. (for PBKDF2)")
	var key = flag.String("k", "", "128-bit key to Encrypt/Decrypt.")
	var pbkdf = flag.String("p", "", "PBKDF2.")
	var random = flag.Bool("r", false, "Generate random 128-bit cryptographic key.")
	var salt = flag.String("s", "", "Salt. (for PBKDF2)")

func main() {
    flag.Parse()

        if (len(os.Args) < 2) {
	fmt.Println("AES Encryption Tool - ALBANESE Lab (c) 2020-2021\n")
	fmt.Println("Usage of",os.Args[0]+":")
        flag.PrintDefaults()
        os.Exit(1)
        }

        if *derive == true {
	prvRaw := pbkdf2.Key([]byte(*pbkdf), []byte(*salt), *iter, 32, sha256.New)
	fmt.Println(hex.EncodeToString(prvRaw))
        os.Exit(1)
	}
	
	if *random == true {
	var key []byte
	var err error
		key = make([]byte, 32)
		_, err = io.ReadFull(rand.Reader, key)
		if err != nil {
                        log.Fatal(err)
		}
		fmt.Println(hex.EncodeToString(key))
        	os.Exit(0)
	}

	var keyHex string
	var prvRaw []byte
	if *pbkdf != "" {
	prvRaw = pbkdf2.Key([]byte(*pbkdf), []byte(*salt), *iter, 32, sha256.New)
	keyHex = hex.EncodeToString(prvRaw)
	} else {
	keyHex = *key
	}
	var key []byte
	var err error
	if keyHex == "" {
		key = make([]byte, 32)
		_, err = io.ReadFull(rand.Reader, key)
		if err != nil {
                        log.Fatal(err)
		}
		fmt.Fprintln(os.Stderr, "Key=", hex.EncodeToString(key))
	} else {
		key, err = hex.DecodeString(keyHex)
		if err != nil {
                        log.Fatal(err)
		}
		if len(key) != 32 {
                        log.Fatal(err)
		}
	}
	ciph, err := aes.NewCipher(key)
	if err != nil {
		log.Fatal(err)
	}
	iv := make([]byte, 16)
	stream := cipher.NewCTR(ciph, iv)
	buf := make([]byte, 64*1<<10)
	var n int
	for {
		n, err = os.Stdin.Read(buf)
		if err != nil && err != io.EOF {
                        log.Fatal(err)
		}
		stream.XORKeyStream(buf[:n], buf[:n])
		if _, err := os.Stdout.Write(buf[:n]); err != nil {
                        log.Fatal(err)
		}
		if err == io.EOF {
			break
		}
	}
        os.Exit(0)
}

Note that the ciphertext has the same length and the same hexdump in both cases.

openssl

As you can see, decrypted text differs from plaintext for some reason and, in some cases, is misinterpreted by the OS.

How to proceed?

Thanks in advace.

@seankhliao
Copy link
Member

Unlike many projects, the Go project does not use GitHub Issues for general discussion or asking questions. GitHub Issues are used for tracking bugs and proposals only.

For questions please refer to https://github.com/golang/go/wiki/Questions

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Sep 20, 2023
@pedroalbanese
Copy link
Author

pedroalbanese commented Sep 20, 2023

@seankhliao

This is a bug and not a question. I'm demonstrating that the Go language works differently than it should. Using the same resources to perform the same operation, there is incompatibility.

Please reopen until you clarify why it works like this and not identically to openssl. You didn't even try to reproduce this.

@pedroalbanese
Copy link
Author

pedroalbanese commented Sep 20, 2023

This code encrypts like the image a diferent output than openssl, bot at same time, is compliant:

package main
import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"flag"
	"fmt"
	"crypto/sha256"
	"golang.org/x/crypto/pbkdf2"
	"io"
	"log"
	"os"
)

	var derive = flag.Bool("d", false, "Derive password-based key.")
	var iter = flag.Int("i", 1024, "Iterations. (for PBKDF2)")
	var key = flag.String("k", "", "128-bit key to Encrypt/Decrypt.")
	var pbkdf = flag.String("p", "", "PBKDF2.")
	var random = flag.Bool("r", false, "Generate random 128-bit cryptographic key.")
	var salt = flag.String("s", "", "Salt. (for PBKDF2)")

func main() {
    flag.Parse()

        if (len(os.Args) < 2) {
	fmt.Println("AES Encryption Tool - ALBANESE Lab (c) 2020-2021\n")
	fmt.Println("Usage of",os.Args[0]+":")
        flag.PrintDefaults()
        os.Exit(1)
        }

        if *derive == true {
	prvRaw := pbkdf2.Key([]byte(*pbkdf), []byte(*salt), *iter, 32, sha256.New)
	fmt.Println(hex.EncodeToString(prvRaw))
        os.Exit(1)
	}
	
	if *random == true {
	var key []byte
	var err error
		key = make([]byte, 32)
		_, err = io.ReadFull(rand.Reader, key)
		if err != nil {
                        log.Fatal(err)
		}
		fmt.Println(hex.EncodeToString(key))
        	os.Exit(0)
	}

	var keyHex string
	var prvRaw []byte
	if *pbkdf != "" {
	prvRaw = pbkdf2.Key([]byte(*pbkdf), []byte(*salt), *iter, 32, sha256.New)
	keyHex = hex.EncodeToString(prvRaw)
	} else {
	keyHex = *key
	}
	var key []byte
	var err error
	if keyHex == "" {
		key = make([]byte, 32)
		_, err = io.ReadFull(rand.Reader, key)
		if err != nil {
                        log.Fatal(err)
		}
		fmt.Fprintln(os.Stderr, "Key=", hex.EncodeToString(key))
	} else {
		key, err = hex.DecodeString(keyHex)
		if err != nil {
                        log.Fatal(err)
		}
		if len(key) != 32 {
                        log.Fatal(err)
		}
	}
	ciph, err := aes.NewCipher(key)
	if err != nil {
		log.Fatal(err)
	}
	iv := make([]byte, 16)
	stream := cipher.NewCTR(ciph, iv)
	buf := make([]byte, 64*1<<10)
	var n int
	for {
		n, err = os.Stdin.Read(buf)
		if err != nil && err != io.EOF {
                        log.Fatal(err)
		}
		stream.XORKeyStream(buf[:n], buf[:n])
		if _, err := os.Stdout.Write(buf[:n]); err != nil {
                        log.Fatal(err)
		}
		if err == io.EOF {
			break
		}
	}
        os.Exit(0)
}

So

echo secret message | thiscode -p 123 -i 2

Must be equal:

echo secret message|openssl enc -aes-256-ctr -md sha256 -pbkdf2 -k 123 -iter 2 -nosalt -iv 00000000000000000000000000000000

In other words, this code is compatible with openssl and is capable of undoing the operation without bugs

echo secret message|openssl enc -aes-256-ctr -md sha256 -pbkdf2 -k 123 -iter 2 -nosalt -iv 00000000000000000000000000000000 | | thiscode -p 123 -i 2

However, there is a coding problem that occurs in Windows 7 and Windows 10 that I noticed, as the commands individually generate different outputs despite having the same hexdump.

openssl2

@pedroalbanese
Copy link
Author

@seankhliao You can try covering the sun with a sieve if you want. Against facts there are no arguments.

@dolmen
Copy link
Contributor

dolmen commented Dec 11, 2023

@pedroalbanese On Windows, the echo command produces "secret message\r\n" while on Unix it produces "secret message\n". The problem is on your side.

@golang golang locked and limited conversation to collaborators Dec 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants