cc20p1305ssh

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2023 License: MIT Imports: 3 Imported by: 0

README

= r00t2.io/cc20p1305ssh
Brent Saner <bts@square-r00t.net>
Last updated {localdatetime}
:doctype: book
:docinfo: shared
:data-uri:
:imagesdir: images
:sectlinks:
:sectnums:
:sectnumlevels: 7
:toc: preamble
:toc2: left
:idprefix:
:toclevels: 7
:source-highlighter: rouge

== What is it?

A Golang library variant of ChaCha20-Poly1305 that OpenSSH uses (`chacha20-poly1305@openssh.com`).

WARNING: Note that this module *only* supports the OpenSSH variant, and should only be used for key generation/parsing/modification/manipulation, not actual connection/stream encryption.

== Usage
The usage of this library is *very* limited in scope; it's only intended for low-level OpenSSH key operations.

Primarily, for use with https://git.r00t2.io/r00t2/go_sshkeys/src/branch/master[go_sshkeys^].

== FAQ

=== Why is this necessary?

Because Golang.org/x/crypto https://github.com/golang/go/issues/36646[removes functionality^] (even for https://github.com/golang/go/issues/44226[very common tech^]) and thinks OpenSSH is a "weird" use case. That's a direct reference; they called it "weird".

I *really, really* hope this library is https://github.com/golang/go/issues/57699[no longer necessary^] by the time I'm done writing it but based on my past experiences with core Golang devs, my expectations are extremely low.

_Narrator: It was still necessary ._

They have no decent support for OpenSSH keys or lower-level operations. And guess what -- sometimes you *need* lower-level functionality. Who knew?

So now because I'm just a single individual, bug fixes will probably lag behind upstream if I have to re-vendor because I'm not maintaining an entire fork of golang.org/x/crypto. All because Golang devs decided the OpenSSH variant was "too weird".

But, of course, not "weird" enough to https://github.com/golang/crypto/blob/3d872d042823aed41f28af3b13beb27c0c9b1e35/ssh/cipher.go#L652[not support the *wire* protocol^] for SSH. Just the key encryption. Because of course. And not publicly exposed either. Because *of course*.

Assholes.

=== Why is the name so ugly?

I couldn't think of a better one and I wanted something notably distinct from the stdlib-x naming.

And module names can't include the `@` symbol.

=== Why don't you expose the rest of low-level ChaCha20/Poly1305/ChaCha20-Poly1305?

* To keep code changes from upstream light (and thus easier to debug, audit, etc.)
* Because otherwise the module name is inaccurate
** Because OpenSSH has their own specific variant
** Which means we can handle SSH-specific functionality if needed
* Because golang.org/x/crypto has made it painfully clear that if you want something that deviates from what they *think* is "best practice", you need to do it yourself
** Which ironically is something they also brand an "anti-pattern" which is just \*chef's kiss*

Documentation

Index

Constants

View Source
const (
	// BlockSize is the size in bytes of the ChaCha20Poly1305 blocks (as used by OpenSSH padding).
	BlockSize int = 8

	/*
		KeySize is the size of the key used by OpenSSH's ChaCha20 implementation.
		It should be KDFKey[:(len(KDFKeySize)-1)/2]. (32 bytes, essentially.)
	*/
	KeySize int = chacha20.KeySize

	/*
		KDFKeySize is the size of the key to return from the chosen KDF.
		At the time of writing, only bcrypt_pbkdf is supported upstream.

		The KDF should return a key of 64 bytes, but OpenSSH only uses the first half for the ChaCha20 key.
		Normally in ChaCha20Poly1305, the second half is used for "additional data".
		OpenSSH keys do not have "additional data".
	*/
	KDFKeySize int = KeySize * 2

	// IvSize is 0 because OpenSSH uses a fixed internal constant (see iv below).
	IvSize int = 0

	/*
		NonceSize is the only reason I need to do this. The actual only reason.

		If this library ever breaks, it's because the chacha20 module was updated but I forgot to change (golang.org/x/crypto/chacha20).NonceSize to 16 instead of 12.
	*/
	NonceSize int = 16

	// PolyKeySize is the amount of the cipher result of chacha20.
	PolyKeySize int = 32

	// TagSize is the length of the Poly1305 tag.
	TagSize int = poly1305.TagSize
)

Variables

View Source
var (
	ErrInvalidKeySize error = errors.New("a key of invalid size was provided; it must be at least 32 bytes")
	ErrInvalidTag           = errors.New("the provided tag does not match the ciphertext")
	ErrInvalidTagSize       = errors.New("a tag of invalid size was provided; it must be at least 16 bytes")
)

Functions

This section is empty.

Types

type ChaCha20Poly1305OpenSSH

type ChaCha20Poly1305OpenSSH struct {
	// contains filtered or unexported fields
}

ChaCha20Poly1305OpenSSH is an implementation of the chacha20poly1305@openssh.com private key cipher.

Use New to return a usable version.

func New

func New(key []byte) (crypter *ChaCha20Poly1305OpenSSH, err error)

New returns a cipher.AEAD from KDF-derived key.

Currently, key should be KDFKeySize bytes and returned by bcrypt_pbkdf as it's currently the only OpenSSH-supported KDF. It is up to the caller to perform the appropriate KDF.

Per the chacha20polycom1305@openssh.com specification, only the first KeySize bytes of key is used for encrypting the private key. The second half (the canonical key is 64 bytes) would be used for traffic purposes, but since this is a static blob it is not used.

If key is nil or <KDFKeySize bytes in length, an error ErrInvalidKeySize will be returned.

*DO NOT USE crypter FOR STREAMS. THIS SHOULD ONLY BE USED TO ENCRYPT AN OPENSSH PRIVATE KEY.*

func (*ChaCha20Poly1305OpenSSH) Decrypt

func (c *ChaCha20Poly1305OpenSSH) Decrypt(ciphertext, tag []byte) (decrypted []byte, err error)

Decrypt decrypts and authenticates ciphertext returning the decrypted format of ciphertext.

If tag is nil or empty, it will be assumed that the tag is appended to the end of ciphertext.

If tag is specified but is <TagSize, an error ErrInvalidTagSize will be returned.

func (*ChaCha20Poly1305OpenSSH) Encrypt

func (c *ChaCha20Poly1305OpenSSH) Encrypt(plaintext []byte) (encrypted, tag []byte, err error)

Encrypt encrypts and authenticates plaintext returning the encrypted format of plaintext.

If polyTag is nil or <TagSize bytes in length, an error ErrInvalidTagSize will be returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL