4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
17 * Copyright (c) 2017, Datto, Inc. All rights reserved.
20 #include <sys/crypto/api.h>
25 hkdf_sha512_extract(uint8_t *salt
, uint_t salt_len
, uint8_t *key_material
,
26 uint_t km_len
, uint8_t *out_buf
)
29 crypto_mechanism_t mech
;
31 crypto_data_t input_cd
, output_cd
;
33 /* initialize HMAC mechanism */
34 mech
.cm_type
= crypto_mech2id(SUN_CKM_SHA512_HMAC
);
36 mech
.cm_param_len
= 0;
38 /* initialize the salt as a crypto key */
39 key
.ck_format
= CRYPTO_KEY_RAW
;
40 key
.ck_length
= CRYPTO_BYTES2BITS(salt_len
);
43 /* initialize crypto data for the input and output data */
44 input_cd
.cd_format
= CRYPTO_DATA_RAW
;
45 input_cd
.cd_offset
= 0;
46 input_cd
.cd_length
= km_len
;
47 input_cd
.cd_raw
.iov_base
= (char *)key_material
;
48 input_cd
.cd_raw
.iov_len
= input_cd
.cd_length
;
50 output_cd
.cd_format
= CRYPTO_DATA_RAW
;
51 output_cd
.cd_offset
= 0;
52 output_cd
.cd_length
= SHA512_DIGEST_LENGTH
;
53 output_cd
.cd_raw
.iov_base
= (char *)out_buf
;
54 output_cd
.cd_raw
.iov_len
= output_cd
.cd_length
;
56 ret
= crypto_mac(&mech
, &input_cd
, &key
, NULL
, &output_cd
, NULL
);
57 if (ret
!= CRYPTO_SUCCESS
)
58 return (SET_ERROR(EIO
));
64 hkdf_sha512_expand(uint8_t *extract_key
, uint8_t *info
, uint_t info_len
,
65 uint8_t *out_buf
, uint_t out_len
)
68 crypto_mechanism_t mech
;
71 crypto_data_t T_cd
, info_cd
, c_cd
;
72 uint_t i
, T_len
= 0, pos
= 0;
74 uint_t N
= (out_len
+ SHA512_DIGEST_LENGTH
) / SHA512_DIGEST_LENGTH
;
75 uint8_t T
[SHA512_DIGEST_LENGTH
];
78 return (SET_ERROR(EINVAL
));
80 /* initialize HMAC mechanism */
81 mech
.cm_type
= crypto_mech2id(SUN_CKM_SHA512_HMAC
);
83 mech
.cm_param_len
= 0;
85 /* initialize the salt as a crypto key */
86 key
.ck_format
= CRYPTO_KEY_RAW
;
87 key
.ck_length
= CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH
);
88 key
.ck_data
= extract_key
;
90 /* initialize crypto data for the input and output data */
91 T_cd
.cd_format
= CRYPTO_DATA_RAW
;
93 T_cd
.cd_raw
.iov_base
= (char *)T
;
95 c_cd
.cd_format
= CRYPTO_DATA_RAW
;
98 c_cd
.cd_raw
.iov_base
= (char *)&c
;
99 c_cd
.cd_raw
.iov_len
= c_cd
.cd_length
;
101 info_cd
.cd_format
= CRYPTO_DATA_RAW
;
102 info_cd
.cd_offset
= 0;
103 info_cd
.cd_length
= info_len
;
104 info_cd
.cd_raw
.iov_base
= (char *)info
;
105 info_cd
.cd_raw
.iov_len
= info_cd
.cd_length
;
107 for (i
= 1; i
<= N
; i
++) {
110 T_cd
.cd_length
= T_len
;
111 T_cd
.cd_raw
.iov_len
= T_cd
.cd_length
;
113 ret
= crypto_mac_init(&mech
, &key
, NULL
, &ctx
, NULL
);
114 if (ret
!= CRYPTO_SUCCESS
)
115 return (SET_ERROR(EIO
));
117 ret
= crypto_mac_update(ctx
, &T_cd
, NULL
);
118 if (ret
!= CRYPTO_SUCCESS
)
119 return (SET_ERROR(EIO
));
121 ret
= crypto_mac_update(ctx
, &info_cd
, NULL
);
122 if (ret
!= CRYPTO_SUCCESS
)
123 return (SET_ERROR(EIO
));
125 ret
= crypto_mac_update(ctx
, &c_cd
, NULL
);
126 if (ret
!= CRYPTO_SUCCESS
)
127 return (SET_ERROR(EIO
));
129 T_len
= SHA512_DIGEST_LENGTH
;
130 T_cd
.cd_length
= T_len
;
131 T_cd
.cd_raw
.iov_len
= T_cd
.cd_length
;
133 ret
= crypto_mac_final(ctx
, &T_cd
, NULL
);
134 if (ret
!= CRYPTO_SUCCESS
)
135 return (SET_ERROR(EIO
));
137 bcopy(T
, out_buf
+ pos
,
138 (i
!= N
) ? SHA512_DIGEST_LENGTH
: (out_len
- pos
));
139 pos
+= SHA512_DIGEST_LENGTH
;
146 * HKDF is designed to be a relatively fast function for deriving keys from a
147 * master key + a salt. We use this function to generate new encryption keys
148 * so as to avoid hitting the cryptographic limits of the underlying
149 * encryption modes. Note that, for the sake of deriving encryption keys, the
150 * info parameter is called the "salt" everywhere else in the code.
153 hkdf_sha512(uint8_t *key_material
, uint_t km_len
, uint8_t *salt
,
154 uint_t salt_len
, uint8_t *info
, uint_t info_len
, uint8_t *output_key
,
158 uint8_t extract_key
[SHA512_DIGEST_LENGTH
];
160 ret
= hkdf_sha512_extract(salt
, salt_len
, key_material
, km_len
,
165 ret
= hkdf_sha512_expand(extract_key
, info
, info_len
, output_key
,