diff --git a/internal/age/recipients_test.go b/internal/age/recipients_test.go index e37d2ae..0be0d17 100644 --- a/internal/age/recipients_test.go +++ b/internal/age/recipients_test.go @@ -19,13 +19,10 @@ import ( ) func TestX25519RoundTrip(t *testing.T) { - var secretKey, publicKey, fileKey [32]byte + var secretKey, publicKey [32]byte if _, err := rand.Read(secretKey[:]); err != nil { t.Fatal(err) } - if _, err := rand.Read(fileKey[:]); err != nil { - t.Fatal(err) - } curve25519.ScalarBaseMult(&publicKey, &secretKey) r, err := age.NewX25519Recipient(publicKey[:]) @@ -41,11 +38,17 @@ func TestX25519RoundTrip(t *testing.T) { t.Errorf("invalid Type values: %v, %v", r.Type(), i.Type()) } + fileKey := make([]byte, 16) + if _, err := rand.Read(fileKey[:]); err != nil { + t.Fatal(err) + } block, err := r.Wrap(fileKey[:]) if err != nil { t.Fatal(err) } - t.Logf("%#v", block) + b := &bytes.Buffer{} + block.Marshal(b) + t.Logf("%s", b.Bytes()) out, err := i.Unwrap(block) if err != nil { @@ -82,7 +85,9 @@ func TestScryptRoundTrip(t *testing.T) { if err != nil { t.Fatal(err) } - t.Logf("%#v", block) + b := &bytes.Buffer{} + block.Marshal(b) + t.Logf("%s", b.Bytes()) out, err := i.Unwrap(block) if err != nil { @@ -125,7 +130,9 @@ func TestSSHRSARoundTrip(t *testing.T) { if err != nil { t.Fatal(err) } - t.Logf("%#v", block) + b := &bytes.Buffer{} + block.Marshal(b) + t.Logf("%s", b.Bytes()) out, err := i.Unwrap(block) if err != nil { @@ -168,7 +175,9 @@ func TestSSHEd25519RoundTrip(t *testing.T) { if err != nil { t.Fatal(err) } - t.Logf("%#v", block) + b := &bytes.Buffer{} + block.Marshal(b) + t.Logf("%s", b.Bytes()) out, err := i.Unwrap(block) if err != nil { diff --git a/internal/age/scrypt.go b/internal/age/scrypt.go index 0bacdef..b702fcb 100644 --- a/internal/age/scrypt.go +++ b/internal/age/scrypt.go @@ -68,7 +68,7 @@ func (r *ScryptRecipient) Wrap(fileKey []byte) (*format.Recipient, error) { if err != nil { return nil, err } - l.Body = []byte(format.EncodeToString(wrappedKey) + "\n") + l.Body = wrappedKey return l, nil } @@ -126,17 +126,13 @@ func (i *ScryptIdentity) Unwrap(block *format.Recipient) ([]byte, error) { if logN <= 0 { return nil, fmt.Errorf("invalid scrypt work factor: %v", logN) } - wrappedKey, err := format.DecodeString(string(block.Body)) - if err != nil { - return nil, fmt.Errorf("failed to parse scrypt recipient: %v", err) - } k, err := scrypt.Key(i.password, salt, 1<") var footerPrefix = []byte("---") +func (r *Recipient) Marshal(w io.Writer) error { + if _, err := w.Write(recipientPrefix); err != nil { + return err + } + for _, a := range append([]string{r.Type}, r.Args...) { + if _, err := io.WriteString(w, " "+a); err != nil { + return err + } + } + if _, err := io.WriteString(w, "\n"); err != nil { + return err + } + for i := 0; i < len(r.Body); i += bytesPerLine { + n := bytesPerLine + if n > len(r.Body)-i { + n = len(r.Body) - i + } + s := EncodeToString(r.Body[i : i+n]) + if _, err := io.WriteString(w, s+"\n"); err != nil { + return err + } + } + return nil +} + func (h *Header) MarshalWithoutMAC(w io.Writer) error { if _, err := io.WriteString(w, intro); err != nil { return err } for _, r := range h.Recipients { - if _, err := w.Write(recipientPrefix); err != nil { - return err - } - for _, a := range append([]string{r.Type}, r.Args...) { - if _, err := io.WriteString(w, " "+a); err != nil { - return err - } - } - if _, err := io.WriteString(w, "\n"); err != nil { - return err - } - // TODO: check that Body ends with a newline. - if _, err := w.Write(r.Body); err != nil { + if err := r.Marshal(w); err != nil { return err } } @@ -132,7 +146,18 @@ func Parse(input io.Reader) (*Header, io.Reader, error) { h.Recipients = append(h.Recipients, r) } else if r != nil { - r.Body = append(r.Body, line...) + b, err := DecodeString(strings.TrimSuffix(string(line), "\n")) + if err != nil { + return nil, nil, errorf("malformed body line %q: %v", line, err) + } + if len(b) > bytesPerLine { + return nil, nil, errorf("malformed body line %q: too long", line) + } + r.Body = append(r.Body, b...) + if len(b) < bytesPerLine { + // Only the last line of a body can be short. + r = nil + } } else { return nil, nil, errorf("unexpected line: %q", line)