github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/grypto/internal/mcf/mcf.go (about) 1 package mcf 2 3 import ( 4 "bytes" 5 "crypto/subtle" 6 "encoding/base64" 7 "errors" 8 ) 9 10 const Divider = '$' 11 12 var ( 13 ErrorInvalidDecodeInput = errors.New("gramework/grypto: invalid mcf input") 14 15 splitDivider = []byte{Divider} 16 ) 17 18 // Encode encodes given providerName, params, salt and key into Modular Crypt Format. 19 func Encode(providerName []byte, params string, salt []byte, key []byte) (res []byte) { 20 salt64 := encodeBase64(salt) 21 key64 := encodeBase64(key) 22 // final res len = len(providerName) + len(params) + len(salt) + len(key) + 4, because we need 4 dividers 23 res = append(res, Divider) 24 res = append(res, providerName...) 25 res = append(res, Divider) 26 res = append(res, params...) 27 res = append(res, Divider) 28 res = append(res, salt64...) 29 res = append(res, Divider) 30 res = append(res, key64...) 31 return res 32 } 33 34 // encodeBase64 encodes the input bytes into standard base64. 35 func encodeBase64(in []byte) (out []byte) { 36 enc := base64.StdEncoding 37 out = make([]byte, enc.EncodedLen(len(in))) 38 enc.Encode(out, in) 39 return out 40 } 41 42 func decodeBase64(in []byte) (out []byte, err error) { 43 enc := base64.StdEncoding 44 out = make([]byte, enc.DecodedLen(len(in))) 45 n, err := enc.Decode(out, in) 46 return out[:n], err 47 } 48 49 // Decode given MCF if it contains information about expected pw type 50 func Decode(mcf []byte, expectedPWType []byte) (providerName []byte, params string, salt []byte, key []byte, err error) { 51 if len(mcf) <= 1 || mcf[0] != Divider { 52 err = ErrorInvalidDecodeInput 53 return 54 } 55 56 parts := bytes.Split(mcf[1:], splitDivider) 57 58 if len(parts) != 4 { 59 err = ErrorInvalidDecodeInput 60 return 61 } 62 63 if subtle.ConstantTimeCompare(parts[0], expectedPWType) == 0 { 64 err = ErrorInvalidDecodeInput 65 return 66 } 67 68 params = string(parts[1]) 69 70 saltDecoded, err := decodeBase64(parts[2]) 71 if err != nil { 72 err = ErrorInvalidDecodeInput 73 return 74 } 75 76 salt = saltDecoded 77 78 keyDecoded, err := decodeBase64(parts[3]) 79 if err != nil { 80 err = ErrorInvalidDecodeInput 81 return 82 } 83 key = keyDecoded 84 return 85 }