• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / iot-manager / 1401702106

05 Aug 2024 08:32PM UTC coverage: 87.577%. Remained the same
1401702106

push

gitlab-ci

web-flow
Merge pull request #295 from mendersoftware/dependabot/docker/docker-dependencies-03b04ac819

chore: bump golang from 1.22.4-alpine3.19 to 1.22.5-alpine3.19 in the docker-dependencies group

3264 of 3727 relevant lines covered (87.58%)

11.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.7
/crypto/crypto.go
1
// Copyright 2022 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package crypto
16

17
import (
18
        "crypto/aes"
19
        "crypto/cipher"
20
        "crypto/hmac"
21
        "crypto/rand"
22
        "crypto/sha512"
23
        "encoding/base64"
24
        "io"
25
        "strings"
26

27
        "github.com/pkg/errors"
28
)
29

30
const V1 byte = 0x1
31
const encryptionKeyLength = 32
32
const hmacSHA512SignatureSizeInBytes = 64
33

34
var (
35
        encryptionKey         = ""
36
        encryptionFallbackKey = ""
37

38
        ErrDecryptionFailed         = errors.New("unable to decrypt the data")
39
        ErrCipherTextTooShort       = errors.New("cipher text is too short")
40
        ErrEncryptionKeyWrongLength = errors.New(
41
                "AES encryption key has a wrong length, expected 32 bytes")
42

43
        // Encode base64 secret in either std or URL encoding ignoring padding.
44
        base64Repl = strings.NewReplacer("-", "+", "_", "/", "=", "")
45
)
46

47
func SetAESEncryptionKey(key string) error {
6✔
48
        if key, err := base64.RawStdEncoding.DecodeString(base64Repl.Replace(key)); err == nil {
11✔
49
                if len(key) > 0 && len(key) != encryptionKeyLength {
6✔
50
                        return ErrEncryptionKeyWrongLength
1✔
51
                }
1✔
52
                encryptionKey = string(key)
4✔
53
        } else {
1✔
54
                return errors.Wrap(err, "failed to base64-decode the AES encryption key")
1✔
55
        }
1✔
56
        return nil
4✔
57
}
58

59
func SetAESEncryptionFallbackKey(key string) error {
6✔
60
        if key, err := base64.RawStdEncoding.DecodeString(base64Repl.Replace(key)); err == nil {
11✔
61
                if len(key) > 0 && len(key) != encryptionKeyLength {
6✔
62
                        return ErrEncryptionKeyWrongLength
1✔
63
                }
1✔
64
                encryptionFallbackKey = string(key)
4✔
65
        } else {
1✔
66
                return errors.Wrap(err, "failed to base64-decode the AES encryption fallback key")
1✔
67
        }
1✔
68
        return nil
4✔
69
}
70

71
func AESEncrypt(data string) ([]byte, error) {
15✔
72
        return encrypt(data, encryptionKey)
15✔
73
}
15✔
74

75
func AESDecrypt(data []byte) (string, error) {
18✔
76
        out, err := decrypt(data, encryptionKey)
18✔
77
        if err == ErrDecryptionFailed {
19✔
78
                out, err = decrypt(data, encryptionFallbackKey)
1✔
79
        }
1✔
80
        return out, err
18✔
81
}
82

83
func encrypt(data string, key string) ([]byte, error) {
15✔
84
        if len(key) == 0 {
17✔
85
                return []byte(data), nil
2✔
86
        }
2✔
87
        block, err := aes.NewCipher([]byte(key))
13✔
88
        if err != nil {
15✔
89
                return nil, err
2✔
90
        }
2✔
91
        dataToEncrypt := []byte(data)
11✔
92
        cipherText := make([]byte, aes.BlockSize+len(dataToEncrypt))
11✔
93
        iv := cipherText[:aes.BlockSize]
11✔
94
        if _, err = io.ReadFull(rand.Reader, iv); err != nil {
11✔
95
                return nil, err
×
96
        }
×
97
        stream := cipher.NewCFBEncrypter(block, iv)
11✔
98
        stream.XORKeyStream(cipherText[aes.BlockSize:], dataToEncrypt)
11✔
99
        // AES and SHA-1 (or SHA-256) are "sufficiently different" that there
11✔
100
        // should be no practical issue with using the same key for AES and HMAC/SHA-*
11✔
101
        // see https://crypto.stackexchange.com/questions/8081/using-the-same-secret-
11✔
102
        // key-for-encryption-and-authentication-in-a-encrypt-then-ma/8086#8086
11✔
103
        HMAC := hmac.New(sha512.New, []byte(key))
11✔
104
        if _, err := HMAC.Write(dataToEncrypt); err != nil {
11✔
105
                return nil, err
×
106
        }
×
107
        result := append([]byte{V1}, append(cipherText, HMAC.Sum(nil)...)...)
11✔
108
        return result, nil
11✔
109
}
110

111
func decrypt(data []byte, key string) (string, error) {
19✔
112
        if len(key) == 0 {
21✔
113
                return string(data), nil
2✔
114
        } else if len(data) < aes.BlockSize {
20✔
115
                return "", ErrCipherTextTooShort
1✔
116
        }
1✔
117

118
        block, err := aes.NewCipher([]byte(key))
16✔
119
        if err != nil {
17✔
120
                return "", errors.Wrap(err, ErrDecryptionFailed.Error())
1✔
121
        }
1✔
122
        if data[0] != V1 {
15✔
123
                return "", ErrDecryptionFailed
×
124
        }
×
125
        signature := data[len(data)-hmacSHA512SignatureSizeInBytes:]
15✔
126
        data = data[1 : len(data)-hmacSHA512SignatureSizeInBytes]
15✔
127
        iv := make([]byte, aes.BlockSize)
15✔
128
        copy(iv, data[:aes.BlockSize])
15✔
129
        cipherData := make([]byte, len(data)-aes.BlockSize)
15✔
130
        copy(cipherData, data[aes.BlockSize:])
15✔
131
        stream := cipher.NewCFBDecrypter(block, iv)
15✔
132
        stream.XORKeyStream(cipherData, cipherData)
15✔
133
        cipherText := string(cipherData)
15✔
134
        //
15✔
135
        HMAC := hmac.New(sha512.New, []byte(key))
15✔
136
        if _, err := HMAC.Write(cipherData); err != nil {
15✔
137
                return "", err
×
138
        }
×
139
        if string(signature) != string(HMAC.Sum(nil)) {
16✔
140
                return "", ErrDecryptionFailed
1✔
141
        }
1✔
142
        return cipherText, err
14✔
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc