1package transit
2
3import (
4	"context"
5	"crypto/sha256"
6	"crypto/sha512"
7	"encoding/base64"
8	"encoding/hex"
9	"fmt"
10	"hash"
11
12	"github.com/hashicorp/vault/sdk/framework"
13	"github.com/hashicorp/vault/sdk/logical"
14)
15
16func (b *backend) pathHash() *framework.Path {
17	return &framework.Path{
18		Pattern: "hash" + framework.OptionalParamRegex("urlalgorithm"),
19		Fields: map[string]*framework.FieldSchema{
20			"input": &framework.FieldSchema{
21				Type:        framework.TypeString,
22				Description: "The base64-encoded input data",
23			},
24
25			"algorithm": &framework.FieldSchema{
26				Type:    framework.TypeString,
27				Default: "sha2-256",
28				Description: `Algorithm to use (POST body parameter). Valid values are:
29
30* sha2-224
31* sha2-256
32* sha2-384
33* sha2-512
34
35Defaults to "sha2-256".`,
36			},
37
38			"urlalgorithm": &framework.FieldSchema{
39				Type:        framework.TypeString,
40				Description: `Algorithm to use (POST URL parameter)`,
41			},
42
43			"format": &framework.FieldSchema{
44				Type:        framework.TypeString,
45				Default:     "hex",
46				Description: `Encoding format to use. Can be "hex" or "base64". Defaults to "hex".`,
47			},
48		},
49
50		Callbacks: map[logical.Operation]framework.OperationFunc{
51			logical.UpdateOperation: b.pathHashWrite,
52		},
53
54		HelpSynopsis:    pathHashHelpSyn,
55		HelpDescription: pathHashHelpDesc,
56	}
57}
58
59func (b *backend) pathHashWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
60	inputB64 := d.Get("input").(string)
61	format := d.Get("format").(string)
62	algorithm := d.Get("urlalgorithm").(string)
63	if algorithm == "" {
64		algorithm = d.Get("algorithm").(string)
65	}
66
67	input, err := base64.StdEncoding.DecodeString(inputB64)
68	if err != nil {
69		return logical.ErrorResponse(fmt.Sprintf("unable to decode input as base64: %s", err)), logical.ErrInvalidRequest
70	}
71
72	switch format {
73	case "hex":
74	case "base64":
75	default:
76		return logical.ErrorResponse(fmt.Sprintf("unsupported encoding format %s; must be \"hex\" or \"base64\"", format)), nil
77	}
78
79	var hf hash.Hash
80	switch algorithm {
81	case "sha2-224":
82		hf = sha256.New224()
83	case "sha2-256":
84		hf = sha256.New()
85	case "sha2-384":
86		hf = sha512.New384()
87	case "sha2-512":
88		hf = sha512.New()
89	default:
90		return logical.ErrorResponse(fmt.Sprintf("unsupported algorithm %s", algorithm)), nil
91	}
92	hf.Write(input)
93	retBytes := hf.Sum(nil)
94
95	var retStr string
96	switch format {
97	case "hex":
98		retStr = hex.EncodeToString(retBytes)
99	case "base64":
100		retStr = base64.StdEncoding.EncodeToString(retBytes)
101	}
102
103	// Generate the response
104	resp := &logical.Response{
105		Data: map[string]interface{}{
106			"sum": retStr,
107		},
108	}
109	return resp, nil
110}
111
112const pathHashHelpSyn = `Generate a hash sum for input data`
113
114const pathHashHelpDesc = `
115Generates a hash sum of the given algorithm against the given input data.
116`
117