Golang equivalent of Java's SHA256withRSA - go

Is there any Golang equivalent of Java's java.security.Signature's SHA256withRSA? A couple of research is that I could not simple calculate the SHA256 hash and then signing it with RSA.

Figured it out if someone stumbled on the same question, here's how it works in Go
func main() {
privateKey := loadPrivateKey()
h := sha256.New()
h.Write([]byte(`your message`))
d := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, d)
if err != nil {
panic(err)
}
fmt.Printf("Signature in byte: %v\n\n", signature)
encodedSig := base64.StdEncoding.EncodeToString(signature)
fmt.Printf("Encoded signature: %v\n\n", encodedSig)
}

Related

How to encrypt a file so that OpenSSL can decrypt it without providing the IV manually

I want to encrypt a file with AES the same way openssl enc command does, so when I want to decrypt it there won't be need for providing IV manually.
In order to decrypt an AES encrypted file you need both key and IV. IV is not a secret and is usually store at the encrypted file.
OpenSSL uses a key derivation function to generate these two using the provided password and a random salt. then after encryption it stores the salt at the header of the file with Salted__ prefix, so at the decryption it could use it along with the password to produce the same key and IV.
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"io"
"os"
"golang.org/x/crypto/pbkdf2"
)
func main() {
keySize := 32;
// its only for demonstration purpose
password := []byte("TESTPASSWORD1234TESTPASSWORD1234");
bReader, err := os.Open("doc.docx")
defer bReader.Close();
if err != nil {
panic(err)
}
salt := make([]byte, 8)
if _, err := io.ReadFull(rand.Reader, salt[:]); err != nil {
panic(err)
}
computed := pbkdf2.Key(password, salt, 10000, keySize + aes.BlockSize , sha256.New)
key := computed[:keySize]
iv := computed[keySize:]
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
bWriter, err := os.Create("doc-encrypted.docx")
if err != nil {
panic(err)
}
defer bWriter.Close()
prefix := []byte("Salted__");
header := append(prefix[:], salt...);
bWriter.Write(header)
sWriter := &cipher.StreamWriter{S: stream, W: bWriter}
if _, err := io.Copy(sWriter, bReader); err != nil {
panic(err)
}
}
and you can decrypt it with openssl enc -in doc-encrypted.docx -out doc-decrypted.docx -d -aes-256-ofb -pbkdf2 -pass pass:TESTPASSWORD1234TESTPASSWORD1234

How I can decode aes-256-cfb

How I can decode aes-256-cfb?
I have file encoded by aes-256-cfb, when I use openssl command
openssl enc -d -aes-256-cfb -salt -pbkdf2 -pass file:encpass -out x.txz -in encpkg
this file is decrypted without any problem,but when I try to decrypt this file by golang, I always get incorrect file, I don't know what my problem is and I hope to find help
my code:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"log"
"os"
)
func main() {
fiencpkg, err := os.ReadFile("encpkg")
if err != nil {
log.Println(err)
os.Exit(1)
}
fiencpass, err := os.ReadFile("encpass")
if err != nil {
log.Println(err)
os.Exit(1)
}
keyb := sha256.Sum256(fiencpass)
block, err := aes.NewCipher(keyb[:])
if err != nil {
panic(err)
}
if len(fiencpkg) < aes.BlockSize {
panic("data too short")
}
iv := fiencpkg[:aes.BlockSize]
decdata := fiencpkg[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(decdata, fiencpkg[aes.BlockSize:])
os.WriteFile("x_go.txz", decdata, 0777)
}
The -pbkdf2 option in the OpenSSL statement causes the PBKDF2 key derivation to be used:
During encryption, a random 8 bytes salt is generated, and together with the password, the key and IV are determined using this key derivation.
Since the salt is needed for decryption, the OpenSSL statement concatenates salt and ciphertext and indicates this with the prefix Salted__.
Thus, during decryption, salt and ciphertext must first be separated:
salt := fiencpkg[8:16]
ciphertext := fiencpkg[16:]
Then key and IV can be derived via PBKDF2 using e.g. the pbkdf2 package:
keyIv := pbkdf2.Key(fiencpass, salt, 10000, 48, sha256.New)
key := keyIv[0:32]
iv := keyIv[32:48]
Note the OpenSSL default values 10000 and SHA256 for iteration count and digest. Since the encryption was done with AES-256-CFB 48 bytes have to be generated (32 bytes for the key, 16 bytes for the IV).
After determining key and IV, decryption can be performed as usual.
Full code:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"log"
"os"
"golang.org/x/crypto/pbkdf2"
)
func main() {
fiencpkg, err := os.ReadFile("encpkg")
if err != nil {
log.Println(err)
os.Exit(1)
}
salt := fiencpkg[8:16]
ciphertext := fiencpkg[16:]
fiencpass, err := os.ReadFile("encpass")
if err != nil {
log.Println(err)
os.Exit(1)
}
keyIv := pbkdf2.Key(fiencpass, salt, 10000, 48, sha256.New)
key := keyIv[0:32]
iv := keyIv[32:48]
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
os.WriteFile("x_go.txz", ciphertext, 0777)
}

Processing data in chunks with io.ReadFull results in corrupted file?

I'm trying to download and decrypt HLS streams by using io.ReadFull to process the data in chunks to conserve memory:
Irrelevant parts of code has been left out for simplicity.
func main() {
f, _ := os.Create(out.ts)
for _, v := range mediaPlaylist {
resp, _ := http.Get(v.URI)
for {
r, err := decryptHLS(key, iv, resp.Body)
if err != nil && err == io.EOF {
break
else if err != nil && err != io.ErrUnexpectedEOF {
panic(err)
}
io.Copy(f, r)
}
}
}
func decryptHLS(key []byte, iv []byte, r io.Reader) (io.Reader, error) {
block, _ := aes.NewCipher(key)
buf := make([]byte, 8192)
mode := cipher.NewCBCDecrypter(block, iv)
n, err := io.ReadFull(r, buf)
if err != nil && err != io.ErrUnexpectedEOF {
return nil, err
}
mode.CryptBlocks(buf, buf)
return bytes.NewReader(buf[:n]), err
}
At first this seems to work as file size is correct and no errors during download,
but the video is corrupted. Not completely as the file is still recognized as a video, but image and sound is distorted.
If I change the code to use ioutil.ReadAll instead, the final video files will no longer be corrupted:
func main() {
f, _ := os.Create(out.ts)
for _, v := range mediaPlaylist {
resp, _ := http.Get(v.URI)
segment, _ := ioutil.ReadAll(resp.Body)
r, _ := decryptHLS(key, iv, &segment)
io.Copy(f, r)
}
}
func decryptHLS(key []byte, iv []byte, s *[]byte) io.Reader {
block, _ := aes.NewCipher(key)
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(*s, *s)
return bytes.NewReader(*s)
}
Any ideas why it works correctly when reading the entire segment into memory, and not when using io.ReadFull and processing it in chunks?
Internally, CBCDecrypter makes a copy of your iv, so subsequent blocks start with the initial IV rather than the one that's been mutated by previous decryptions.
Create the decrypter once, and you should be able to keep re-using it to decrypt block by block (assuming the block size is a multiple of the block size expected by this crypto algorithm).

Failing to verify ECDSA signature

I have a signature:
3044022014d647cd08f1ea5b31d1e6539b6cbceb9182f6e7b2e29fb969354ef7e3434923022028bb4eda36af410149baa936322e7c0e46cc5540a3aa89c811bc3c360028bfd301
a hash
f27c6c3aa42563c958292922be1e53fe107f4db0dfadba11122f0b12bf77f3ab
and a pubkey
04b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e6537a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b
Below is my Go code to verify the signature but it fails! I have information that the three pieces should validate OK and some other person has verified them in other ways. So I want to kown what mistake in this Go code make me get the false result.
if you want more information,this link is about how i build my signature and how someone say he success verify in other ways. I feel helpless now:
https://bitcointalk.org/index.php?topic=4879014.msg43992837#msg43992837
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/hex"
"fmt"
"math/big"
)
func main() {
pubkey, err := hex.DecodeString("b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e6537a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b")
if err != nil {
panic(err)
}
curve := elliptic.P256()
// length
keyLen := len(pubkey)
x := big.Int{}
y := big.Int{}
x.SetBytes(pubkey[:(keyLen / 2)])
y.SetBytes(pubkey[(keyLen / 2):])
rawPubKey := ecdsa.PublicKey{curve, &x, &y}
// hash
hash, err := hex.DecodeString("f27c6c3aa42563c958292922be1e53fe107f4db0dfadba11122f0b12bf77f3ab")
if err != nil {
panic(err)
}
r := big.Int{}
s := big.Int{}
rr, err := hex.DecodeString("14d647cd08f1ea5b31d1e6539b6cbceb9182f6e7b2e29fb969354ef7e3434923")
if err != nil {
panic(err)
}
ss, err := hex.DecodeString("28bb4eda36af410149baa936322e7c0e46cc5540a3aa89c811bc3c360028bfd3")
if err != nil {
panic(err)
}
r.SetBytes(rr)
s.SetBytes(ss)
fmt.Printf("%v\n", ecdsa.Verify(&rawPubKey, hash[:], &r, &s))
}
You are trying to use the wrong curve. P-256, also known as secp256r1, is not the same as the curve used in Bitcoin, which is secp256k1. Your public key doesn’t correspond to a point on P-256 (you can check with curve.IsOnCurve(&x, &y)), but it is a point on secp256k1.
Golang doesn’t include support for the Bitcoin curve, so you will need to find a library that does ECDSA using it.
I can confirm that signature does verify that data for that key if you use the correct curve.

Convert os.Stdin to []byte

I'm trying to implement a small chat-server in golang with end-to-end encryption. Starting of the example for server https://github.com/adonovan/gopl.io/tree/master/ch8/chat and client https://github.com/adonovan/gopl.io/blob/master/ch8/netcat3/netcat.go I stumbled upon https://www.thepolyglotdeveloper.com/2018/02/encrypt-decrypt-data-golang-application-crypto-packages/ to encrypt and decrypt in Go.
The function to encrypt:
func encrypt(data []byte, passphrase string) []byte {
block, _ := aes.NewCipher([]byte(createHash(passphrase)))
gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext
}
in func main():
ciphertext := encrypt([]byte(os.Stdin), "password")
mustCopy(conn, ciphertext)
conn.Close()
os.Stdin is os.file, while it is needed as []byte. The solution should be io.Reader or via buffer, but I can't find a working solution.
I tried
bytes.NewBuffer([]byte(os.Stdin))
and
reader := bytes.NewReader(os.Stdin)
Any input is more than welcome. Sorry if I'm not seeing the obvious problem/solution here, as I'm fairly new.
os.Stdin is an io.Reader. You can't convert it to a []byte, but you can read from it, and the data you read from it, that may be read into a []byte.
Since in many terminals reading from os.Stdin gives data by lines, you should read a complete line from it. Reading from os.Stdin might block until a complete line is available.
For that you have many possibilities, one is to use bufio.Scanner.
This is how you can do it:
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() {
log.Printf("Failed to read: %v", scanner.Err())
return
}
line := scanner.Bytes() // line is of type []byte, exactly what you need

Resources