@@ -30,13 +30,14 @@ func CipherAES256(key []byte) (Cipher, error) {
30
30
if err != nil {
31
31
return nil , err
32
32
}
33
- digest := sha256 .Sum256 (key )
34
- return & aes256 {aead : aead , digest : digest [:] }, nil
33
+ digest := fmt . Sprintf ( "%x" , sha256 .Sum256 (key ))[: 7 ]
34
+ return & aes256 {aead : aead , digest : digest }, nil
35
35
}
36
36
37
37
type aes256 struct {
38
- aead cipher.AEAD
39
- digest []byte
38
+ aead cipher.AEAD
39
+ // digest is the first 7 bytes of the hex-encoded SHA-256 digest of aead.
40
+ digest string
40
41
}
41
42
42
43
func (a * aes256 ) Encrypt (plaintext []byte ) ([]byte , error ) {
@@ -60,5 +61,54 @@ func (a *aes256) Decrypt(ciphertext []byte) ([]byte, error) {
60
61
}
61
62
62
63
func (a * aes256 ) HexDigest () string {
63
- return fmt .Sprintf ("%x" , a .digest )
64
+ return a .digest
65
+ }
66
+
67
+ type CipherDigest string
68
+ type Ciphers struct {
69
+ primary string
70
+ m map [string ]Cipher
71
+ }
72
+
73
+ // CiphersAES256 returns a new Ciphers instance with the given ciphers.
74
+ // The first cipher in the list is the primary cipher. Any ciphers after the
75
+ // first are considered secondary ciphers and are only used for decryption.
76
+ func CiphersAES256 (cs ... Cipher ) Ciphers {
77
+ var primary string
78
+ m := make (map [string ]Cipher )
79
+ for idx , c := range cs {
80
+ m [c .HexDigest ()] = c
81
+ if idx == 0 {
82
+ primary = c .HexDigest ()
83
+ }
84
+ }
85
+ return Ciphers {primary : primary , m : m }
86
+ }
87
+
88
+ // Encrypt encrypts the given plaintext using the primary cipher and returns the
89
+ // ciphertext. The ciphertext is prefixed with the primary cipher's digest.
90
+ func (cs Ciphers ) Encrypt (plaintext []byte ) ([]byte , error ) {
91
+ c , ok := cs .m [cs .primary ]
92
+ if ! ok {
93
+ return nil , xerrors .Errorf ("no ciphers configured" )
94
+ }
95
+ prefix := []byte (c .HexDigest () + "-" )
96
+ crypted , err := c .Encrypt (plaintext )
97
+ if err != nil {
98
+ return nil , err
99
+ }
100
+ return append (prefix , crypted ... ), nil
101
+ }
102
+
103
+ // Decrypt decrypts the given ciphertext using the cipher indicated by the
104
+ // ciphertext's prefix. The prefix is the first 7 bytes of the hex-encoded
105
+ // SHA-256 digest of the cipher's key. Decryption will fail if the prefix
106
+ // does not match any of the configured ciphers.
107
+ func (cs Ciphers ) Decrypt (ciphertext []byte ) ([]byte , error ) {
108
+ requiredPrefix := string (ciphertext [:7 ])
109
+ c , ok := cs .m [requiredPrefix ]
110
+ if ! ok {
111
+ return nil , xerrors .Errorf ("missing required decryption cipher %s" , requiredPrefix )
112
+ }
113
+ return c .Decrypt (ciphertext [8 :])
64
114
}
0 commit comments