diff options
Diffstat (limited to 'internal/cryptokit/cryptokit_test.go')
| -rw-r--r-- | internal/cryptokit/cryptokit_test.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/internal/cryptokit/cryptokit_test.go b/internal/cryptokit/cryptokit_test.go new file mode 100644 index 0000000..928120e --- /dev/null +++ b/internal/cryptokit/cryptokit_test.go @@ -0,0 +1,156 @@ +package cryptokit + +import ( + "bytes" + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "encoding/base64" + "encoding/pem" + "os" + "os/exec" + "testing" + + "filippo.io/age" + "golang.org/x/crypto/ssh" +) + +func TestEd25519SignVerifyAcceptsSeedEncoding(t *testing.T) { + public, private, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + message := []byte("Aegis cryptographic test") + signature, err := SignEd25519(message, base64.StdEncoding.EncodeToString(private.Seed())) + if err != nil { + t.Fatal(err) + } + if err := VerifyEd25519(message, signature, base64.StdEncoding.EncodeToString(public)); err != nil { + t.Fatal(err) + } + if err := VerifyEd25519([]byte("tampered"), signature, base64.StdEncoding.EncodeToString(public)); err == nil { + t.Fatal("tampered message verified") + } +} + +func TestEd25519PublicKeyAndFingerprint(t *testing.T) { + public, private, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + derived, err := Ed25519PublicKey(base64.StdEncoding.EncodeToString(private.Seed())) + if err != nil { + t.Fatal(err) + } + if derived != base64.StdEncoding.EncodeToString(public) { + t.Fatalf("derived public key = %q, want %q", derived, base64.StdEncoding.EncodeToString(public)) + } + fingerprint, err := Ed25519PublicKeyFingerprint(derived) + if err != nil { + t.Fatal(err) + } + if len(fingerprint) != len("sha256:")+64 || fingerprint[:len("sha256:")] != "sha256:" { + t.Fatalf("unexpected fingerprint %q", fingerprint) + } +} + +func TestAgeRoundTrip(t *testing.T) { + identity, err := age.GenerateX25519Identity() + if err != nil { + t.Fatal(err) + } + ciphertext, err := EncryptAge([]byte("age test"), identity.Recipient().String()) + if err != nil { + t.Fatal(err) + } + plaintext, err := DecryptAge(ciphertext, identity.String()) + if err != nil { + t.Fatal(err) + } + if string(plaintext) != "age test" { + t.Fatalf("unexpected plaintext %q", plaintext) + } +} + +func TestAgeSSHCompatibility(t *testing.T) { + testKey := func(private any) { + signer, err := ssh.NewSignerFromKey(private) + if err != nil { + t.Fatal(err) + } + privatePEM, err := ssh.MarshalPrivateKey(private, "") + if err != nil { + t.Fatal(err) + } + ciphertext, err := EncryptAge([]byte("age SSH test"), string(ssh.MarshalAuthorizedKey(signer.PublicKey()))) + if err != nil { + t.Fatal(err) + } + plaintext, err := DecryptAge(ciphertext, string(pem.EncodeToMemory(privatePEM))) + if err != nil { + t.Fatal(err) + } + if string(plaintext) != "age SSH test" { + t.Fatalf("unexpected plaintext %q", plaintext) + } + } + _, edPrivate, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + testKey(edPrivate) + rsaPrivate, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + testKey(rsaPrivate) +} + +func TestOpenPGPRoundTripWithUserKeyMaterial(t *testing.T) { + gpg, err := exec.LookPath("gpg") + if err != nil { + t.Skip("gpg is not installed") + } + home := t.TempDir() + if err := os.Chmod(home, 0o700); err != nil { + t.Fatal(err) + } + run := func(args []string, input []byte) ([]byte, error) { + cmd := exec.Command(gpg, append([]string{"--batch", "--no-tty", "--no-options", "--homedir", home}, args...)...) + cmd.Stdin = bytes.NewReader(input) + return cmd.Output() + } + if _, err := run([]string{"--pinentry-mode", "loopback", "--passphrase", "", "--quick-generate-key", "Aegis Test <aegis@example.invalid>", "rsa2048", "sign", "1d"}, nil); err != nil { + t.Skipf("gpg cannot create an ephemeral test key: %v", err) + } + if _, err := run([]string{"--pinentry-mode", "loopback", "--passphrase", "", "--quick-add-key", "aegis@example.invalid", "rsa2048", "encrypt", "1d"}, nil); err != nil { + t.Skipf("gpg cannot create an ephemeral encryption subkey: %v", err) + } + publicKey, err := run([]string{"--armor", "--export", "aegis@example.invalid"}, nil) + if err != nil { + t.Fatal(err) + } + privateKey, err := run([]string{"--armor", "--export-secret-keys", "aegis@example.invalid"}, nil) + if err != nil { + t.Fatal(err) + } + message := []byte("OpenPGP compatibility test") + signature, err := SignOpenPGPDetached(message, string(privateKey)) + if err != nil { + t.Fatal(err) + } + if err := VerifyOpenPGPDetached(message, signature, string(publicKey)); err != nil { + t.Fatal(err) + } + ciphertext, err := EncryptOpenPGP(message, string(publicKey), string(privateKey)) + if err != nil { + t.Fatal(err) + } + plaintext, err := DecryptOpenPGP([]byte(ciphertext), string(privateKey)) + if err != nil { + t.Fatal(err) + } + if string(plaintext) != string(message) { + t.Fatalf("unexpected plaintext %q", plaintext) + } +} |
