Golang rsa x509 ParsePKIXPublicKey error - go

I'm getting some strange situation with parsing just-created rsa keys.
In this part I generate new pair and write into file:
rsaKey,err:= rsa.GenerateKey(rand.Reader,2048)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
publicKey := rsaKey.PublicKey
outFile, err := os.Create("./private.pem")
defer outFile.Close()
var privateKey = &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
}
err = pem.Encode(outFile, privateKey)
asn1Bytes, err := asn1.Marshal(publicKey)
var pemkey = &pem.Block{
Type: "PUBLIC KEY",
Bytes: asn1Bytes,
}
pemfile, err := os.Create("./public.pem")
defer pemfile.Close()
err = pem.Encode(pemfile, pemkey)
Next step is reading key from file and parse it:
data, err := ioutil.ReadFile("./public.pem")
block, _ :=pem.Decode(data)
res,err := x509.ParsePKIXPublicKey(block.Bytes)
fmt.Print(err)
But x509.ParsePKIXPublicKey(block.Bytes) return error:
asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:257 isCompound:false}) {optional:false explicit:false application:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier #4
playground example
https://play.golang.org/p/djlK8lO5_E2
Please help me solve this issue.

Related

Golang crypto/rsa problem decrypting text using private key from PEM file

So i'm building a basic generator/encryptor/decryptor for RSA keys in Golang.
I have four main functions.
GenKeys() generates the key pair using rsa.GenerateKey, then writes this private key to a pem file.
GetKeys() Gets the private key from the pem file.
Encrypt() Encrypts a string manually entered into the console and then spits out the ciphertext
Decrypt() Takes in the cipher text and decrypts it, using the GetKeys function to get the private key from the pem file.
The GenKeys function works fine. And the Encrypt function works fine. Entering a string and spitting out a cipher text.
But I get crypto/rsa: decryption error when I run the decrypt flag.
Tried:
The private key is identical when I gen the key to when i Import it again from the pem file.
Ive tried the different decryption methods included in the crypto package.
I've tried just importing the ciphertext directly from the encrypt method into the decrypt, just in case there was a problem when spitting it out to console.
To note:
This worked when I only wrote the private key to memory, instead of spitting it out to a file, which tells me that something is going wrong when importing the key again from the pem file. But I cant figure out what.
Please if somebody could look through my code and tell me if im missing something I'd be eternaly grateful.
main.go
func main() {
var action = flag.String("action", "", "Whether to decrypt or encrypt")
flag.Parse()
task := *action
var err error
if task == "gen" {
//gen the priv key and write to file
err = services.GenKeys()
if err != nil {
fmt.Println("Could not generate keys:", err)
}
}
if task == "encrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
return
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the text you would like to encrypt: ")
text, _ := reader.ReadString('\n')
cipherText, err := services.Encrypt(&privateKey.PublicKey, text)
if err != nil {
fmt.Println("Could not encrypt", err)
return
}
fmt.Printf("Encrypted message: %x", cipherText)
}
if task == "decrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the cypher text you would like to decrypt: ")
text, _ := reader.ReadString('\n')
decryptedText, err := services.Decrypt(privateKey, []byte(text))
if err != nil {
fmt.Println("Could not decrypt text", err.Error())
return
}
fmt.Println("decrypted text: ", string(decryptedText))
}
}
crypto_service.go
func Encrypt(pub *rsa.PublicKey, text string) ([]byte, error) {
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
pub,
[]byte(text),
nil)
if err != nil {
return nil, err
}
return encryptedBytes, nil
}
func Decrypt(privKey *rsa.PrivateKey, cipherText []byte) ([]byte, error) {
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), nil, privKey, cipherText, nil)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}
gen_keys_service.go
func GenKeys() error {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
privFile, err := os.Create("private_key.pem")
if err != nil {
return err
}
pemData := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
}
err = pem.Encode(privFile, pemData)
if err != nil {
return err
}
privFile.Close()
fmt.Println("Your keys have been written to private_key.pem")
return nil
}
func GetKeys() (*rsa.PrivateKey, error) {
file, err := os.Open("private_key.pem")
if err != nil {
return nil, err
}
defer file.Close()
//Create a byte slice (pemBytes) the size of the file size
pemFileInfo, _ := file.Stat()
var size = pemFileInfo.Size()
pemBytes := make([]byte, size)
//Create new reader for the file and read into pemBytes
buffer := bufio.NewReader(file)
_, err = buffer.Read(pemBytes)
if err != nil {
return nil, err
}
//Now decode the byte slice
data, _ := pem.Decode(pemBytes)
if data == nil {
return nil, errors.New("could not read pem file")
}
privKeyImport, err := x509.ParsePKCS1PrivateKey(data.Bytes)
if err != nil {
return nil, err
}
return privKeyImport, nil
}
Oh and heres the format of my pem file:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApX2AUrhtH3FHSds3JAWmBDZcSwixydY/M52WmWfqDmQDRc6X
V4FqLyiEIMSq3Z7zOR9GH4a2Ps3HPlTvJa2EGkgKDk7hVRWlocbQvRsdSk/aEZ7U
O0SgB6s0H2/9MdWsXaJHADuUJYlSgG+VH7vf5uIi4w8OKNfmHfB7uJQJByb4+8jg
rzMFgmFyEUnWOgUh3dXtdV1XD5BPQiDk2D8vYR8JUjK9uWHVMaR2y51uK3vNZHmR
/ce1g36Gzhl5aRfUqJ8gWLCsJ42VEDHznz04YvrH/DRrcuSb/65JlpQMOKr9wdf/
/sILXkeEylifeZoUENRbgIz5UCyyQtTrfCMcDwIDAQABAoIBAQCBVx41CKlY2rsh
0TA+eh+vySDHECuMGWPaHn92tE2tI6OfKoEERkRMSTlDNxJoFfP4oCW5PBsx6Lih
UdZ7Nys5MzaQyju4uStzziSUuB1jWBeSj/VFwTPl6nvZWjike2C06cDeQLJfx/zw
HsWJQNgU5obnuXuSlnLm0W6Q6zpHGH/GdtS6O5kLjLySgb87xDTivdKEH5iqUNRe
fs6WTJpsKsT92lT/AcO/QUuw7sK/GSW2spnzO8xF4ZdQhjj72NkWqa/K/ncfKhuk
eI/+1HPvSru+nOJts6j3Xd98EQbIDBVZLArl6gB49B6UsEogAYgRJAs5mIIHzxRS
YfiQckzRAoGBAMijQPc+ygZ9pTNLOCi7zHQtHHOj8lMGuqQKTFsDIxVGI7Iy6tm/
CQbbpZiQiDoskCSJq3pWcydu+csDmdq/PrTJ4yuJMAgUaOItvuNu5vS3nOGPiJBl
0zDERW2GA0jcE4STreVM5GR3kOgNG8EIbmjVC1eQqhKK7a0+kPbYqYBnAoGBANMn
e6VcmL19WNIEYHyXLdCOaPj7LOMmAA2SNRA7V4YkaXbgRSHmnHboHEVzytSJH9gY
mmZ9+8dkq9n+ODi1vn2hCR9TIJHapn8aWHOqgnZesJ2xThV78S8Kp8jZD4lx8Ejy
5t3TMVIZ6hQXWfkQjpKs3QAXJszrZR0Cb0sJOp4ZAoGAVb3mmoKbxXBWc/g2NLok
4pUQrp6mhTK/+jBodxB9Iq9Ju/KkiI9qJSMivnMttGas5uBqhqqBJZ34Y/jS/Dd0
bcBFM6q5+wn11IqmI/2V94isI3y6aLMLMLD/1pFJwA5EzQhrbS2SARlTtMc9UB3x
SR2abj5lX+09KycsvkDTFwsCgYEAhG4b509W4GlQHo/uL9XlPwtCHP3zXhdEKz7K
lv6Q2ynVF2B7G1L2SME0kf6YdIn39eEgXS2gjqK+AX+mpTKfYU1xWjsZj0CR8d+F
IC4Nms2yeYRtU54jWvyU1KwGSY6zRB1L3E4LfdGQ9L7ciA/xS16tUNQ0Wos8JGCV
inskT2kCgYBg4zzkUAmQ75hlRsM0r7ezrx4xt8GHrlxwOTeQYgVcymiSSMXVITNI
ByBfs+wqV7PrXjM69xPdV/CHczFcA7g/M0o0CJZhWead403knjZmGFlZypvWskOT
aK4nArJ0zaS7FGhCe24QORYZPGjCzg7dLKhKDvK1PB4ogRVo4dDckA==
-----END RSA PRIVATE KEY-----
In the encryption part the ciphertext is displayed hex encoded. If it is entered hex encoded in the decryption part, it must be hex decoded accordingly, which is missing in the posted code. The hex decoding can be done with the hex package.
Also, as mentioned in Peter's comment, the trailing newline must be removed, e.g. with strings.TrimSuffix(). Alternatively, fmt.Scan() or bufio.Scanner can be used instead of bufio.Reader. The last two options do not return the trailing newline.
Possible implementation (for simplicity without exception handling):
...
var text string
fmt.Println("Please enter the ciphertext you would like to decrypt: ")
fmt.Scan(&text)
textHexDec, _ := hex.DecodeString(text)
decryptedText, _ := Decrypt(privateKey, textHexDec)
fmt.Println("Decrypted text: ", string(decryptedText))
...

Decrypting a non ASCII armored PGP file in Go

Is it possible to decrypt binary .PGP file with Go's "golang.org/x/crypto/openpgp" library?
The following code works with an armored ASCII encoded file but throws EOF error with a binary PGP file. Is there a similar function to armor.Decode() that allows for the binary file to be decrypted?
func DecryptFile(encryptedFilePath string, decryptedFilePath string) error {
pubKey := decodePublicKey()
privKey := decodePrivateKey()
entity := createEntityFromKeys(pubKey, privKey)
file := readFile(encryptedFilePath)
block, err := armor.Decode(file)
if err != nil {
log.Printf("Error reading OpenPGP Armor: %s", err)
return err
}
if block.Type != "Message" {
log.Println("Invalid message type")
return err
}
var entityList openpgp.EntityList
entityList = append(entityList, entity)
messageDetails, err := openpgp.ReadMessage(block.Body, entityList, nil, nil)
if err != nil {
log.Printf("Error reading message: %s", err)
return err
}
compressed, err := gzip.NewReader(messageDetails.UnverifiedBody)
if err != nil {
log.Printf("Invalid compression level: %s", err)
return err
}
defer compressed.Close()
buffer := bytes.NewBuffer(nil)
n, err := io.Copy(buffer, compressed)
if err != nil {
log.Printf("Error reading encrypted file: %s", err)
return err
}
err = ioutil.WriteFile(decryptedFilePath, buffer.Bytes(), 0644)
if err != nil {
log.Println(err)
return err
}
log.Printf("Decrypted %d bytes\n", n)
return nil
}
I encountered the same exact problem with PGP, also got EOF on my first trial.
The encrypted file is in binary(.pgp)
The private/public key in key ring armored file(.asc) like this:
----BEGIN PGP PUBLIC KEY BLOCK-----
-----END PGP PRIVATE KEY BLOCK-----
Here is the code that I use:
keyRing, err := os.Open("keyArmoredFile.asc")
if err != nil {
log.Fatal(err)
}
entityList, err := openpgp.ReadArmoredKeyRing(keyRing)
if err != nil {
log.Fatal(err)
}
entity := entityList[0]
passphraseByte := []byte("password")
err = entity.PrivateKey.Decrypt(passphraseByte)
if err != nil {
log.Fatal(err)
}
for _, subkey := range entity.Subkeys {
subkey.PrivateKey.Decrypt(passphraseByte)
}
encryptedContent, err := os.Open("encryptedFile.pgp")
if err != nil {
log.Fatal(err)
}
md, err := openpgp.ReadMessage(encryptedContent, entityList, nil, nil)
if err != nil {
log.Fatal(err)}
bytes, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
log.Fatal(err)
}
// decryption result
decStr := string(bytes)
Reference:
https://gist.github.com/stuart-warren/93750a142d3de4e8fdd2

Parsing X509 certificate in Go

I am having the following function, which reads an X509 certificate.
certCerFile,err := os.Open("certificate.pem")
if err != nil {
log.Fatal(err)
}
derBytes := make([]byte,1000)
count,err:=certCerFile.Read(derBytes)
if err != nil {
log.Fatal(err)
}
certCerFile.Close()
// trim the bytes to actual length in call
cert,err := x509.ParseCertificate(derBytes[0:count])
if err != nil {
log.Fatal(err)
}
fmt.Printf("Name %s\n", cert.Subject.CommonName)
fmt.Printf("Not before %s\n", cert.NotBefore.String())
fmt.Printf("Not after %s\n", cert.NotAfter.String())
I face the following error:
asn1: structure error: tags don't match (16 vs {class:0 tag:13 length:45 isCompound:true}) {optional:false explicit:false application:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} certificate #2
That's how I generate X509:
random := rand.Reader
var key rsa.PrivateKey
loadKey("private.key",&key)
now:= time.Now()
then := now.Add(60 * 60 * 24 * 365 * 1000 * 1000 * 1000)
template:= x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "borscht.com",
Organization: []string{"Borscht Systems AG"},
},
NotBefore:now,
NotAfter:then,
SubjectKeyId: []byte{1,2,3,4},
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
BasicConstraintsValid:true,
IsCA:true,
DNSNames:[]string{"borscht.com","localhost"},
}
derBytes,err:=x509.CreateCertificate(random, &template, &template,&key.PublicKey,&key)
if err != nil {
log.Fatal(err)
}
certCerFile,err :=os.Create("certificate.cer")
if err != nil {
log.Fatal(err)
}
certCerFile.Write(derBytes)
certCerFile.Close()
certPemFile, err := os.Create("certificate.pem")
if err != nil {
log.Fatal(err)
}
I just don't understand what might be wrong.
I made a mistake myself. Parse pem instead of cer file. Replaced and everything is fine

JWT key is invalid

I am following this example https://www.youtube.com/watch?v=eVlxuST7dCA to make a jwt auth. When I run the code below I get "Key is invalid" error. When I try printing tokenString it is empty. The GitHub to this sample is https://github.com/potatogopher/jwt-go-example/blob/master/server.go Why am I getting invalid error?
var privateKey []byte
privateKey, err := ioutil.ReadFile("demo.rsa")
token := jwt.New(jwt.GetSigningMethod("RS256"))
tokenString, err := token.SignedString(privateKey)
fmt.Println("TOKEN:", tokenString)
I think the example code you're referring to uses an outdated API of jwt-go. The RS256 signing method requires the key to be a rsa.PrivateKey and not a byte buffer. This means, that the private key first has to be parsed using the jwt.ParseRSAPrivateKeyFromPEMfunction.
I've updated your example below:
func main() {
tokenString, err := createSignedTokenString()
if err != nil {
panic(err)
}
fmt.Printf("Signed token string:\n%v\n", tokenString)
token, err := parseTokenFromSignedTokenString(tokenString)
if err != nil {
panic(err)
}
fmt.Printf("Parsed token valid = %v, raw token:\n%v\n", token.Valid, token.Raw)
}
func createSignedTokenString() (string, error) {
privateKey, err := ioutil.ReadFile("demo.rsa")
if err != nil {
return "", fmt.Errorf("error reading private key file: %v\n", err)
}
key, err := jwt.ParseRSAPrivateKeyFromPEM(privateKey)
if err != nil {
return "", fmt.Errorf("error parsing RSA private key: %v\n", err)
}
token := jwt.New(jwt.SigningMethodRS256)
tokenString, err := token.SignedString(key)
if err != nil {
return "", fmt.Errorf("error signing token: %v\n", err)
}
return tokenString, nil
}
func parseTokenFromSignedTokenString(tokenString string) (*jwt.Token, error) {
publicKey, err := ioutil.ReadFile("demo.rsa.pub")
if err != nil {
return nil, fmt.Errorf("error reading public key file: %v\n", err)
}
key, err := jwt.ParseRSAPublicKeyFromPEM(publicKey)
if err != nil {
return nil, fmt.Errorf("error parsing RSA public key: %v\n", err)
}
parsedToken, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return key, nil
})
if err != nil {
return nil, fmt.Errorf("error parsing token: %v", err)
}
return parsedToken, nil
}
You need to create the private key with this command: openssl genrsa -out demo.rsa
If you dont want to do that, you can also use the hmac signing method where you only have to supply a secret key/string.
Example:
key := []byte("test")
token := jwt.New(jwt.SigningMethodHS256)
tokenString, err := token.SignedString(key)
fmt.Println("TOKEN:", tokenString)

Load encrypted PKCS1 private key from file

I have a PKCS1 private key in a file and I load it using
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
Then, I try to convert it into private key object
block, _ := pem.Decode(b)
der, err := x509.DecryptPEMBlock(block, []byte("qwerty"))
if err != nil {
return nil, err
}
bytes := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: der})
return x509.ParsePKCS1PrivateKey(bytes)
But this code throws exception in DecryptPEMBlock
x509: no DEK-Info header in block
I didn't find any documentation about this in golang
I made a mistake with my private key file and here is a working code
func GetPrivateKey(path string) (*rsa.PrivateKey, error) {
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(b)
der, err := x509.DecryptPEMBlock(block, []byte(*PrivateKeyPassword))
if err != nil {
return nil, err
}
return x509.ParsePKCS1PrivateKey(der)
}
P.S. Go does have a package to decrypt PKCS1 private keys, but does not have for PKCS8.
Go does not have package to decode PKCS files it seems
Checkout this link for more details PKCS
I cant find a package to decode PKCS1 keys
Use this package to decode the PKCS8 files, there are some packages to decode PKCS8, PKCS10, PKCS12 but not for PKCS1

Resources