Skip to content

Commit

Permalink
Merge pull request #17 from srounce/private-key-passphrase
Browse files Browse the repository at this point in the history
Feat: Allow users to provide private key passphrase
  • Loading branch information
Mic92 committed Dec 24, 2022
2 parents a0bd769 + 6e73e98 commit 8d5c5a5
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
nixPath:
- nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-22.05.tar.gz
- nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-22.11.tar.gz
- nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixpkgs-unstable.tar.gz
os: [ ubuntu-latest, macos-latest ]
runs-on: ${{ matrix.os }}
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ $ cat key.txt
AGE-SECRET-KEY-1K3VN4N03PTHJWSJSCCMQCN33RY5FSKQPJ4KRRTG3JMQUYE0TUSEQEDH6V8
```

If you private key is encrypted, you can export the password in `SSH_TO_AGE_PASSPHRASE`

``` console
$ read -s SSH_TO_AGE_PASSPHRASE; export SSH_TO_AGE_PASSPHRASE
$ ssh-to-age -private-key -i $HOME/.ssh/id_ed25519 -o key.txt
```

- Exports the public key:

```console
Expand Down
13 changes: 10 additions & 3 deletions cmd/ssh-to-age/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"errors"
"flag"
"fmt"
sshage "github.com/Mic92/ssh-to-age"
"io"
"io/ioutil"
"os"
"strings"

sshage "github.com/Mic92/ssh-to-age"
)

type options struct {
Expand Down Expand Up @@ -63,9 +64,15 @@ func convertKeys(args []string) error {
}
defer writer.Close()
}

if opts.privateKey {
key, _, err := sshage.SSHPrivateKeyToAge(sshKey)
var (
key *string
err error
)

keyPassphrase := os.Getenv("SSH_TO_AGE_PASSPHRASE")

key, _, err = sshage.SSHPrivateKeyToAge(sshKey, []byte(keyPassphrase))
if err != nil {
return fmt.Errorf("failed to convert '%s': %w", sshKey, err)
}
Expand Down
28 changes: 25 additions & 3 deletions cmd/ssh-to-age/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ func TestSshKeyScan(t *testing.T) {

file, err := os.Open(out)
ok(t, err)
defer file.Close()
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
for scanner.Scan() {
pubKey := strings.TrimSuffix(scanner.Text(), "\n")
fmt.Printf("scanned key: %s\n", pubKey)
_, err = age.ParseX25519Recipient(pubKey)
ok(t, err)
}
}
ok(t, scanner.Err())
}

Expand All @@ -92,3 +92,25 @@ func TestPrivateKey(t *testing.T) {
_, err = age.ParseX25519Identity(privateKey)
ok(t, err)
}

func TestPrivateKeyWithPassphrase(t *testing.T) {
tempdir := TempDir(t)
defer os.RemoveAll(tempdir)
out := path.Join(tempdir, "out")

passphrase := "test"

os.Setenv("SSH_TO_AGE_PASSPHRASE", passphrase)
defer os.Unsetenv("SSH_TO_AGE_PASSPHRASE")

err := convertKeys([]string{"ssh-to-age", "-private-key", "-i", Asset("id_ed25519_passphrase"), "-o", out})
ok(t, err)

rawPrivateKey, err := ioutil.ReadFile(out)
privateKey := strings.TrimSuffix(string(rawPrivateKey), "\n")
ok(t, err)

fmt.Printf("private key: %s\n", privateKey)
_, err = age.ParseX25519Identity(privateKey)
ok(t, err)
}
8 changes: 8 additions & 0 deletions cmd/ssh-to-age/test-assets/id_ed25519_passphrase
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABC83l/B2p
MGlU+7xBT7wzeuAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAID/+AcTjBdIG6Xwk
4ZiuckvG5xNDlaqX316bKGo6D3a5AAAAkJA09klC9kTXa4VO1n4p3/J0ugw89MNS4eUn2b
4vbCPGrqZGZBU/Byu4A5g/Z03sGxGJj0GqnkC6I8aS2aTeQriNpdm10NaPVRL9dtL0//rp
NT/WAPFTUavHyBT16tmKKabyKHHf83QdtpbjckXkk8q1Xf8tBKYooZJcieo+22mrmq1Hha
JxU9TKx2Tc2RMymQ==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions cmd/ssh-to-age/test-assets/id_ed25519_passphrase.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/+AcTjBdIG6Xwk4ZiuckvG5xNDlaqX316bKGo6D3a5
15 changes: 11 additions & 4 deletions convert.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package agessh

import (
"crypto"
"crypto/ed25519"
"crypto/sha512"
"crypto"
"errors"
"fmt"
"reflect"
Expand Down Expand Up @@ -57,8 +57,16 @@ func encodePublicKey(key crypto.PublicKey) (*string, error) {
return &s, nil
}

func SSHPrivateKeyToAge(sshKey []byte) (*string, *string, error) {
privateKey, err := ssh.ParseRawPrivateKey(sshKey)
func SSHPrivateKeyToAge(sshKey, passphrase []byte) (*string, *string, error) {
var (
privateKey interface{}
err error
)
if len(passphrase) > 0 {
privateKey, err = ssh.ParseRawPrivateKeyWithPassphrase(sshKey, passphrase)
} else {
privateKey, err = ssh.ParseRawPrivateKey(sshKey)
}
if err != nil {
return nil, nil, fmt.Errorf("failed to parse ssh private key: %w", err)
}
Expand All @@ -85,7 +93,6 @@ func SSHPrivateKeyToAge(sshKey []byte) (*string, *string, error) {
return &s, pubKey, nil
}


func SSHPublicKeyToAge(sshKey []byte) (*string, error) {
var err error
var pk ssh.PublicKey
Expand Down

0 comments on commit 8d5c5a5

Please sign in to comment.