From 25f9ee044d7927448bbc60e0bbc73d43102dbf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=94=CE=B7=CE=BC=CE=AE=CF=84=CF=81=CE=B7=CF=82=20=CE=A1?= =?UTF-8?q?=CE=B1=CE=B2=CE=B9=CF=8C=CE=BB=CE=BF=CF=82?= Date: Tue, 21 Dec 2021 04:43:42 +0200 Subject: [PATCH] feat(vault 1.2): added support for the ansible vault v1.2 payload format (#10) --- decrypt_test.go | 14 ++++++++++++++ encrypt.go | 41 +++++++++++++++++++++++++++++++++++++++++ encrypt_test.go | 15 +++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/decrypt_test.go b/decrypt_test.go index 2fd04fc..e6d2a4a 100644 --- a/decrypt_test.go +++ b/decrypt_test.go @@ -19,6 +19,20 @@ func Test_Decrypt(t *testing.T) { assert.NoError(t, err) } +func Test_Decrypt_v2(t *testing.T) { + password := "asdf" + content := `$ANSIBLE_VAULT;1.2;AES256;label +39663038636438383965366163636163376531336238346239623934393436393938656439643133 +3638363066366433666438623138373866393763373265320a366635386630336562633763323236 +61616562393964666464653532636436346535616566613434613361303734373734383930323661 +6664306264366235630a643235323438646132656337613434396338396335396439346336613062 +3766 +` + result, err := Decrypt(content, password) + assert.Equal(t, "hello", result) + assert.NoError(t, err) +} + func Test_DecryptFile(t *testing.T) { password := "asdf" filename := "./testdata/test1/secrets.yaml" diff --git a/encrypt.go b/encrypt.go index 1c20884..1ac71fa 100644 --- a/encrypt.go +++ b/encrypt.go @@ -42,6 +42,20 @@ func Encrypt(body, password string) (result string, err error) { return } +// see https://docs.ansible.com/ansible/latest/user_guide/vault.html#ansible-vault-payload-format-1-1-1-2 +func Encrypt2(body, password, label string) (result string, err error) { + salt, err := GenerateRandomBytes(32) + check(err) + // salt_64 := "2262970e2309d5da757af6c473b0ed3034209cc0d48a3cc3d648c0b174c22fde" + // salt,_ = hex.DecodeString(salt_64) + key1, key2, iv := genKeyInitctr(password, salt) + ciphertext := createCipherText(body, key1, iv) + combined := combineParts(ciphertext, key2, salt) + vaultText := hex.EncodeToString([]byte(combined)) + result = formatOutput2(vaultText, label) + return +} + func createCipherText(body string, key1, iv []byte) []byte { bs := aes.BlockSize padding := (bs - len(body)%bs) @@ -103,3 +117,30 @@ func formatOutput(vaultText string) string { whole := strings.Join(elements, "\n") return whole } + +func formatOutput2(vaultText, labelText string) string { + heading := "$ANSIBLE_VAULT" + version := "1.2" + cipherName := "AES256" + + headerElements := make([]string, 4) + headerElements[0] = heading + headerElements[1] = version + headerElements[2] = cipherName + headerElements[3] = labelText + header := strings.Join(headerElements, ";") + + elements := make([]string, 1) + elements[0] = header + for i := 0; i < len(vaultText); i += 80 { + end := i + 80 + if end > len(vaultText) { + end = len(vaultText) + } + elements = append(elements, vaultText[i:end]) + } + elements = append(elements, "") + + whole := strings.Join(elements, "\n") + return whole +} diff --git a/encrypt_test.go b/encrypt_test.go index 1eaaad2..407e4c3 100644 --- a/encrypt_test.go +++ b/encrypt_test.go @@ -18,3 +18,18 @@ func Test_Encrypt(t *testing.T) { assert.NoError(t, err) assert.Equal(t, body, result) } + +func Test_Encrypt_v2(t *testing.T) { + password := "asdf" + body := "secret" + label := "label" + var encrypted string + var err error + encrypted, err = Encrypt2(body, password, label) + assert.NoError(t, err) + + var result string + result, err = Decrypt(encrypted, password) + assert.NoError(t, err) + assert.Equal(t, body, result) +}