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_length
= CRYPTO_BYTES2BITS(salt_len
);
42 /* initialize crypto data for the input and output data */
43 input_cd
.cd_format
= CRYPTO_DATA_RAW
;
44 input_cd
.cd_offset
= 0;
45 input_cd
.cd_length
= km_len
;
46 input_cd
.cd_raw
.iov_base
= (char *)key_material
;
47 input_cd
.cd_raw
.iov_len
= input_cd
.cd_length
;
49 output_cd
.cd_format
= CRYPTO_DATA_RAW
;
50 output_cd
.cd_offset
= 0;
51 output_cd
.cd_length
= SHA512_DIGEST_LENGTH
;
52 output_cd
.cd_raw
.iov_base
= (char *)out_buf
;
53 output_cd
.cd_raw
.iov_len
= output_cd
.cd_length
;
55 ret
= crypto_mac(&mech
, &input_cd
, &key
, NULL
, &output_cd
);
56 if (ret
!= CRYPTO_SUCCESS
)
57 return (SET_ERROR(EIO
));
63 hkdf_sha512_expand(uint8_t *extract_key
, uint8_t *info
, uint_t info_len
,
64 uint8_t *out_buf
, uint_t out_len
)
67 crypto_mechanism_t mech
;
70 crypto_data_t T_cd
, info_cd
, c_cd
;
71 uint_t i
, T_len
= 0, pos
= 0;
73 uint_t N
= (out_len
+ SHA512_DIGEST_LENGTH
) / SHA512_DIGEST_LENGTH
;
74 uint8_t T
[SHA512_DIGEST_LENGTH
];
77 return (SET_ERROR(EINVAL
));
79 /* initialize HMAC mechanism */
80 mech
.cm_type
= crypto_mech2id(SUN_CKM_SHA512_HMAC
);
82 mech
.cm_param_len
= 0;
84 /* initialize the salt as a crypto key */
85 key
.ck_length
= CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH
);
86 key
.ck_data
= extract_key
;
88 /* initialize crypto data for the input and output data */
89 T_cd
.cd_format
= CRYPTO_DATA_RAW
;
91 T_cd
.cd_raw
.iov_base
= (char *)T
;
93 c_cd
.cd_format
= CRYPTO_DATA_RAW
;
96 c_cd
.cd_raw
.iov_base
= (char *)&c
;
97 c_cd
.cd_raw
.iov_len
= c_cd
.cd_length
;
99 info_cd
.cd_format
= CRYPTO_DATA_RAW
;
100 info_cd
.cd_offset
= 0;
101 info_cd
.cd_length
= info_len
;
102 info_cd
.cd_raw
.iov_base
= (char *)info
;
103 info_cd
.cd_raw
.iov_len
= info_cd
.cd_length
;
105 for (i
= 1; i
<= N
; i
++) {
108 T_cd
.cd_length
= T_len
;
109 T_cd
.cd_raw
.iov_len
= T_cd
.cd_length
;
111 ret
= crypto_mac_init(&mech
, &key
, NULL
, &ctx
);
112 if (ret
!= CRYPTO_SUCCESS
)
113 return (SET_ERROR(EIO
));
115 ret
= crypto_mac_update(ctx
, &T_cd
);
116 if (ret
!= CRYPTO_SUCCESS
)
117 return (SET_ERROR(EIO
));
119 ret
= crypto_mac_update(ctx
, &info_cd
);
120 if (ret
!= CRYPTO_SUCCESS
)
121 return (SET_ERROR(EIO
));
123 ret
= crypto_mac_update(ctx
, &c_cd
);
124 if (ret
!= CRYPTO_SUCCESS
)
125 return (SET_ERROR(EIO
));
127 T_len
= SHA512_DIGEST_LENGTH
;
128 T_cd
.cd_length
= T_len
;
129 T_cd
.cd_raw
.iov_len
= T_cd
.cd_length
;
131 ret
= crypto_mac_final(ctx
, &T_cd
);
132 if (ret
!= CRYPTO_SUCCESS
)
133 return (SET_ERROR(EIO
));
135 memcpy(out_buf
+ pos
, T
,
136 (i
!= N
) ? SHA512_DIGEST_LENGTH
: (out_len
- pos
));
137 pos
+= SHA512_DIGEST_LENGTH
;
144 * HKDF is designed to be a relatively fast function for deriving keys from a
145 * master key + a salt. We use this function to generate new encryption keys
146 * so as to avoid hitting the cryptographic limits of the underlying
147 * encryption modes. Note that, for the sake of deriving encryption keys, the
148 * info parameter is called the "salt" everywhere else in the code.
151 hkdf_sha512(uint8_t *key_material
, uint_t km_len
, uint8_t *salt
,
152 uint_t salt_len
, uint8_t *info
, uint_t info_len
, uint8_t *output_key
,
156 uint8_t extract_key
[SHA512_DIGEST_LENGTH
];
158 ret
= hkdf_sha512_extract(salt
, salt_len
, key_material
, km_len
,
163 ret
= hkdf_sha512_expand(extract_key
, info
, info_len
, output_key
,