package crypto

import "git.sr.ht/~shulhan/pakakeh.go/lib/crypto"

Package crypto provide a wrapper for standard crypto package and golang.org/x/crypto.

Index

Examples

Variables

var ErrEmptyPassphrase = errors.New(`empty passphrase`)

ErrEmptyPassphrase returned when private key is encrypted and loaded interactively, using LoadPrivateKeyInteractive, but the readed passphrase is empty.

This is to catch error "bcrypt_pbkdf: empty password" earlier that cannot be catched using errors.Is after ssh.ParseRawPrivateKeyWithPassphrase.

var ErrStdinPassphrase = errors.New(`cannot read passhprase from stdin`)

ErrStdinPassphrase error when program cannot changes os.Stdin for reading passphrase in terminal. The original error message is "inappropriate ioctl for device".

Functions

func DecryptOaep

func DecryptOaep(hash hash.Hash, random io.Reader, pkey *rsa.PrivateKey, cipher, label []byte) (plain []byte, err error)

DecryptOaep extend the rsa.DecryptOAEP to make it able to decrypt a message larger than its public modulus size.

func EncryptOaep

func EncryptOaep(hash hash.Hash, random io.Reader, pub *rsa.PublicKey, msg, label []byte) (cipher []byte, err error)

EncryptOaep extend the rsa.EncryptOAEP to make it able to encrypt a message larger than its than (public modulus size - 2*hash.Size - 2).

The function signature is the same with rsa.EncryptOAEP except the name, to make it distinguishable.

func LoadPrivateKey

func LoadPrivateKey(file string, passphrase []byte) (pkey crypto.PrivateKey, err error)

LoadPrivateKey read and parse PEM formatted private key from file. This is a wrapper for ssh.ParseRawPrivate that can return either *dsa.PrivateKey, ecdsa.PrivateKey, *ed25519.PrivateKey, or *rsa.PrivateKey.

The passphrase is optional and will only be used if the private key is encrypted. If its set it will use ssh.ParseRawPrivateKeyWithPassphrase.

Example

ExampleLoadPrivateKey test loading private key from file and convert the returned type to original type.

Code:

{
	var (
		file string
		err  error
		pkey crypto.PrivateKey
		ok   bool
	)

	// RSA key with PKCS#8 generated using openssl v3.1.2,
	//	$ openssl genpkey -algorithm rsa -out openssl_rsa.key

	file = `testdata/openssl_rsa.key`
	pkey, err = LoadPrivateKey(file, nil)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*rsa.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *rsa.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T from %s\n", pkey, file)

	// ecdsa key generated using openssl v3.1.2,
	//	$ openssl ecparam -name prime256v1 -genkey -noout -out openssl_ecdsa.key

	file = `testdata/openssl_ecdsa.key`
	pkey, err = LoadPrivateKey(file, nil)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*ecdsa.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *ecdsa.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T from %s\n", pkey, file)

	// ed25519 key generated using openssh v9.4p1-4.

	file = `testdata/openssh_ed25519.key`
	pkey, err = LoadPrivateKey(file, nil)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*ed25519.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *ed25519.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T from %s\n", pkey, file)

	// Output:
	// Loaded *rsa.PrivateKey from testdata/openssl_rsa.key
	// Loaded *ecdsa.PrivateKey from testdata/openssl_ecdsa.key
	// Loaded *ed25519.PrivateKey from testdata/openssh_ed25519.key
}

Output:

Loaded *rsa.PrivateKey from testdata/openssl_rsa.key
Loaded *ecdsa.PrivateKey from testdata/openssl_ecdsa.key
Loaded *ed25519.PrivateKey from testdata/openssh_ed25519.key
Example (WithPassphrase)

RSA key with PKCS#8 generated using openssl v3.1.2,

$ openssl genpkey -algorithm rsa -out openssl_rsa.key

and then encrypted using passphrase,

$ cp openssl_rsa.key openssl_rsa_pass.key
$ ssh-keygen -p -f openssl_rsa_pass.key -N s3cret

Using openssl to encrypt private key will cause the LoadPrivateKey return an error,

unsupported key type "ENCRYPTED PRIVATE KEY"

ecdsa key generated using openssl v3.1.2,

$ openssl ecparam -name prime256v1 -genkey -noout \
	-out openssl_ecdsa.key

and then ecrypted using passphrase,

$ openssl ec -aes256 -in openssl_ecdsa.key -out \
	openssl_ecdsa_pass.key -passout pass:s3cret

ed25519 key generated using openssh v9.4p1-4,

$ ssh-keygen -t ed25519 -f openssh_ed25519.key

and then encrypted using passphrase,

$ cp openssh_ed25519.key openssh_ed25519_pass.key
$ ssh-keygen -p -f openssh_ed25519_pass.key -N s3cret

Code:

{
	var (
		passphrase = []byte(`s3cret`)

		file string
		err  error
		pkey crypto.PrivateKey
		ok   bool
	)

	file = `testdata/openssl_rsa_pass.key`
	pkey, err = LoadPrivateKey(file, passphrase)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*rsa.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *rsa.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T with passphrase from %s\n", pkey, file)

	file = `testdata/openssl_ecdsa_pass.key`
	pkey, err = LoadPrivateKey(file, passphrase)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*ecdsa.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *ecdsa.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T with passphrase from %s\n", pkey, file)

	file = `testdata/openssh_ed25519_pass.key`
	pkey, err = LoadPrivateKey(file, passphrase)
	if err != nil {
		log.Fatalf(`%s: %s`, file, err)
	}

	_, ok = pkey.(*ed25519.PrivateKey)
	if !ok {
		log.Fatalf(`expecting *ed25519.PrivateKey, got %T`, pkey)
	}
	fmt.Printf("Loaded %T with passphrase from %s\n", pkey, file)

	// Output:
	// Loaded *rsa.PrivateKey with passphrase from testdata/openssl_rsa_pass.key
	// Loaded *ecdsa.PrivateKey with passphrase from testdata/openssl_ecdsa_pass.key
	// Loaded *ed25519.PrivateKey with passphrase from testdata/openssh_ed25519_pass.key
}

Output:

Loaded *rsa.PrivateKey with passphrase from testdata/openssl_rsa_pass.key
Loaded *ecdsa.PrivateKey with passphrase from testdata/openssl_ecdsa_pass.key
Loaded *ed25519.PrivateKey with passphrase from testdata/openssh_ed25519_pass.key

func LoadPrivateKeyInteractive

func LoadPrivateKeyInteractive(termrw io.ReadWriter, file string) (pkey crypto.PrivateKey, err error)

LoadPrivateKeyInteractive load the private key from file. If the private key file is encrypted, it will prompt for the passphrase from terminal or from program defined in SSH_ASKPASS environment variable.

The termrw parameter is optional, default to os.Stdin if its nil. Its provide as reader-and-writer to prompt and read password from terminal (or for testing).

The SSH_ASKPASS is controlled by environment SSH_ASKPASS_REQUIRE.

See ssh(1) manual page for more information.

Source Files

crypto.go

Version
v0.60.0 (latest)
Published
Feb 1, 2025
Platform
linux/amd64
Imports
12 packages
Last checked
9 hours ago

Tools for package owners.