Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/libs/rfc3961.py: 2%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

637 statements  

1# SPDX-License-Identifier: BSD-2-Clause 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (c) 2013, Marc Horowitz 

5# Copyright (C) 2013, Massachusetts Institute of Technology 

6# Copyright (C) 2022-2024, Gabriel Potter and the secdev/scapy community 

7 

8""" 

9Implementation of cryptographic functions for Kerberos 5 

10 

11- RFC 3961: Encryption and Checksum Specifications for Kerberos 5 

12- RFC 3962: Advanced Encryption Standard (AES) Encryption for Kerberos 5 

13- RFC 4757: The RC4-HMAC Kerberos Encryption Types Used by Microsoft Windows 

14- RFC 6113: A Generalized Framework for Kerberos Pre-Authentication 

15- RFC 8009: AES Encryption with HMAC-SHA2 for Kerberos 5 

16 

17.. note:: 

18 You will find more complete documentation for Kerberos over at 

19 `SMB <https://scapy.readthedocs.io/en/latest/layers/kerberos.html>`_ 

20""" 

21 

22# TODO: support cipher states... 

23 

24__all__ = [ 

25 "ChecksumType", 

26 "EncryptionType", 

27 "InvalidChecksum", 

28 "KRB_FX_CF2", 

29 "Key", 

30 "SP800108_KDFCTR", 

31 "_rfc1964pad", 

32] 

33 

34# The following is a heavily modified version of 

35# https://github.com/SecureAuthCorp/impacket/blob/3ec59074ec35c06bbd4312d1042f0e23f4a1b41f/impacket/krb5/crypto.py 

36# itself heavily inspired from 

37# https://github.com/mhorowitz/pykrb5/blob/master/krb5/crypto.py 

38# Note that the following work is based only on THIS COMMIT from impacket, 

39# which is therefore under mhorowitz's BSD 2-clause "simplified" license. 

40 

41import abc 

42import enum 

43import math 

44import os 

45import struct 

46from scapy.compat import ( 

47 orb, 

48 chb, 

49 int_bytes, 

50 bytes_int, 

51 plain_str, 

52) 

53 

54# Typing 

55from typing import ( 

56 Any, 

57 Callable, 

58 List, 

59 Optional, 

60 Type, 

61 Union, 

62) 

63 

64# We end up using our own crypto module for hashes / hmac because 

65# we need MD4 which was dropped everywhere. It's just a wrapper above 

66# the builtin python ones (except for MD4). 

67 

68from scapy.layers.tls.crypto.hash import ( 

69 _GenericHash, 

70 Hash_MD4, 

71 Hash_MD5, 

72 Hash_SHA, 

73 Hash_SHA256, 

74 Hash_SHA384, 

75) 

76from scapy.layers.tls.crypto.h_mac import ( 

77 Hmac, 

78 Hmac_MD5, 

79 Hmac_SHA, 

80) 

81 

82# For everything else, use cryptography. 

83 

84try: 

85 from cryptography.hazmat.primitives import hashes 

86 from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC 

87 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 

88 

89 try: 

90 # cryptography > 43.0 

91 from cryptography.hazmat.decrepit.ciphers import ( 

92 algorithms as decrepit_algorithms, 

93 ) 

94 except ImportError: 

95 decrepit_algorithms = algorithms 

96except ImportError: 

97 raise ImportError("To use kerberos cryptography, you need to install cryptography.") 

98 

99 

100# cryptography's TripleDES allow the usage of a 56bit key, which thus behaves like DES 

101DES = decrepit_algorithms.TripleDES 

102 

103 

104# https://go.microsoft.com/fwlink/?LinkId=186039 

105# https://csrc.nist.gov/CSRC/media/Publications/sp/800-108/archive/2008-11-06/documents/sp800-108-Nov2008.pdf 

106# [SP800-108] section 5.1 (used in [MS-SMB2] sect 3.1.4.2) 

107 

108 

109def SP800108_KDFCTR( 

110 K_I: bytes, 

111 Label: bytes, 

112 Context: bytes, 

113 L: int, 

114 hashmod: _GenericHash = Hash_SHA256, 

115) -> bytes: 

116 """ 

117 KDF in Counter Mode as section 5.1 of [SP800-108] 

118 

119 This assumes r=32, and defaults to SHA256 ([MS-SMB2] default). 

120 """ 

121 PRF = Hmac(K_I, hashmod).digest 

122 h = hashmod.hash_len 

123 n = math.ceil(L / h) 

124 if n >= 0xFFFFFFFF: 

125 # 2^r-1 = 0xffffffff with r=32 per [MS-SMB2] 

126 raise ValueError("Invalid n value in SP800108_KDFCTR") 

127 result = b"".join( 

128 PRF(struct.pack(">I", i) + Label + b"\x00" + Context + struct.pack(">I", L)) 

129 for i in range(1, n + 1) 

130 ) 

131 return result[: L // 8] 

132 

133 

134# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1 

135 

136 

137class EncryptionType(enum.IntEnum): 

138 DES_CBC_CRC = 1 

139 DES_CBC_MD4 = 2 

140 DES_CBC_MD5 = 3 

141 # DES3_CBC_SHA1 = 7 

142 DES3_CBC_SHA1_KD = 16 

143 AES128_CTS_HMAC_SHA1_96 = 17 

144 AES256_CTS_HMAC_SHA1_96 = 18 

145 AES128_CTS_HMAC_SHA256_128 = 19 

146 AES256_CTS_HMAC_SHA384_192 = 20 

147 RC4_HMAC = 23 

148 RC4_HMAC_EXP = 24 

149 # CAMELLIA128-CTS-CMAC = 25 

150 # CAMELLIA256-CTS-CMAC = 26 

151 

152 

153# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2 

154 

155 

156class ChecksumType(enum.IntEnum): 

157 CRC32 = 1 

158 RSA_MD4 = 2 

159 RSA_MD4_DES = 3 

160 # RSA_MD5 = 7 

161 RSA_MD5_DES = 8 

162 # RSA_MD5_DES3 = 9 

163 # SHA1 = 10 

164 HMAC_SHA1_DES3_KD = 12 

165 # HMAC_SHA1_DES3 = 13 

166 # SHA1 = 14 

167 HMAC_SHA1_96_AES128 = 15 

168 HMAC_SHA1_96_AES256 = 16 

169 # CMAC-CAMELLIA128 = 17 

170 # CMAC-CAMELLIA256 = 18 

171 HMAC_SHA256_128_AES128 = 19 

172 HMAC_SHA384_192_AES256 = 20 

173 HMAC_MD5 = -138 

174 

175 

176class InvalidChecksum(ValueError): 

177 pass 

178 

179 

180######### 

181# Utils # 

182######### 

183 

184 

185# https://www.gnu.org/software/shishi/ides.pdf - APPENDIX B 

186 

187 

188def _n_fold(s, n): 

189 # type: (bytes, int) -> bytes 

190 """ 

191 n-fold is an algorithm that takes m input bits and "stretches" them 

192 to form n output bits with equal contribution from each input bit to 

193 the output (quote from RFC 3961 sect 3.1). 

194 """ 

195 

196 def rot13(y, nb): 

197 # type: (bytes, int) -> bytes 

198 x = bytes_int(y) 

199 mod = (1 << (nb * 8)) - 1 

200 if nb == 0: 

201 return y 

202 elif nb == 1: 

203 return int_bytes(((x >> 5) | (x << (nb * 8 - 5))) & mod, nb) 

204 else: 

205 return int_bytes(((x >> 13) | (x << (nb * 8 - 13))) & mod, nb) 

206 

207 def ocadd(x, y, nb): 

208 # type: (bytearray, bytearray, int) -> bytearray 

209 v = [a + b for a, b in zip(x, y)] 

210 while any(x & ~0xFF for x in v): 

211 v = [(v[i - nb + 1] >> 8) + (v[i] & 0xFF) for i in range(nb)] 

212 return bytearray(x for x in v) 

213 

214 m = len(s) 

215 lcm = n // math.gcd(n, m) * m # lcm = math.lcm(n, m) on Python>=3.9 

216 buf = bytearray() 

217 for _ in range(lcm // m): 

218 buf += s 

219 s = rot13(s, m) 

220 out = bytearray(b"\x00" * n) 

221 for i in range(0, lcm, n): 

222 out = ocadd(out, buf[i : i + n], n) 

223 return bytes(out) 

224 

225 

226def _zeropad(s, padsize): 

227 # type: (bytes, int) -> bytes 

228 """ 

229 Return s padded with 0 bytes to a multiple of padsize. 

230 """ 

231 return s + b"\x00" * (-len(s) % padsize) 

232 

233 

234def _rfc1964pad(s): 

235 # type: (bytes) -> bytes 

236 """ 

237 Return s padded as RFC1964 mandates 

238 """ 

239 pad = (-len(s)) % 8 

240 return s + pad * struct.pack("!B", pad) 

241 

242 

243def _xorbytes(b1, b2): 

244 # type: (bytearray, bytearray) -> bytearray 

245 """ 

246 xor two strings together and return the resulting string 

247 """ 

248 assert len(b1) == len(b2) 

249 return bytearray((x ^ y) for x, y in zip(b1, b2)) 

250 

251 

252def _mac_equal(mac1, mac2): 

253 # type: (bytes, bytes) -> bool 

254 # Constant-time comparison function. (We can't use HMAC.verify 

255 # since we use truncated macs.) 

256 return all(x == y for x, y in zip(mac1, mac2)) 

257 

258 

259# https://doi.org/10.6028/NBS.FIPS.74 sect 3.6 

260 

261WEAK_DES_KEYS = set( 

262 [ 

263 # 1 

264 b"\xe0\x01\xe0\x01\xf1\x01\xf1\x01", 

265 b"\x01\xe0\x01\xe0\x01\xf1\x01\xf1", 

266 # 2 

267 b"\xfe\x1f\xfe\x1f\xfe\x0e\xfe\x0e", 

268 b"\x1f\xfe\x1f\xfe\x0e\xfe\x0e\xfe", 

269 # 3 

270 b"\xe0\x1f\xe0\x1f\xf1\x0e\xf1\x0e", 

271 b"\x1f\xe0\x1f\xe0\x0e\xf1\x0e\xf1", 

272 # 4 

273 b"\x01\xfe\x01\xfe\x01\xfe\x01\xfe", 

274 b"\xfe\x01\xfe\x01\xfe\x01\xfe\x01", 

275 # 5 

276 b"\x01\x1f\x01\x1f\x01\x0e\x01\x0e", 

277 b"\x1f\x01\x1f\x01\x0e\x01\x0e\x01", 

278 # 6 

279 b"\xe0\xfe\xe0\xfe\xf1\xfe\xf1\xfe", 

280 b"\xfe\xe0\xfe\xe0\xfe\xf1\xfe\xf1", 

281 # 7 

282 b"\x01" * 8, 

283 # 8 

284 b"\xfe" * 8, 

285 # 9 

286 b"\xe0" * 4 + b"\xf1" * 4, 

287 # 10 

288 b"\x1f" * 4 + b"\x0e" * 4, 

289 ] 

290) 

291 

292# fmt: off 

293CRC32_TABLE = [ 

294 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 

295 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 

296 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 

297 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 

298 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 

299 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 

300 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 

301 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 

302 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 

303 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 

304 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 

305 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 

306 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 

307 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 

308 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 

309 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 

310 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 

311 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 

312 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 

313 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 

314 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 

315 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 

316 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 

317 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 

318 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 

319 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 

320 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 

321 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 

322 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 

323 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 

324 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 

325 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 

326 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 

327 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 

328 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 

329 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 

330 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 

331 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 

332 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 

333 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 

334 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 

335 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 

336 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 

337 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 

338 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 

339 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 

340 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 

341 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 

342 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 

343 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 

344 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 

345 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 

346 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 

347 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 

348 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 

349 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 

350 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 

351 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 

352 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 

353 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 

354 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 

355 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 

356 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 

357 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 

358] 

359# fmt: on 

360 

361############ 

362# RFC 3961 # 

363############ 

364 

365 

366# RFC3961 sect 3 

367 

368 

369class _EncryptionAlgorithmProfile(abc.ABCMeta): 

370 """ 

371 Base class for etype profiles. 

372 

373 Usable etype classes must define: 

374 :attr etype: etype number 

375 :attr keysize: protocol size of key in bytes 

376 :attr seedsize: random_to_key input size in bytes 

377 :attr reqcksum: 'required checksum mechanism' per RFC3961. 

378 this is the default checksum used for this algorithm. 

379 :attr random_to_key: (if the keyspace is not dense) 

380 :attr string_to_key: 

381 :attr encrypt: 

382 :attr decrypt: 

383 :attr prf: 

384 """ 

385 

386 etype = None # type: EncryptionType 

387 keysize = None # type: int 

388 seedsize = None # type: int 

389 reqcksum = None # type: ChecksumType 

390 

391 @classmethod 

392 @abc.abstractmethod 

393 def derive(cls, key, constant): 

394 # type: (Key, bytes) -> bytes 

395 pass 

396 

397 @classmethod 

398 @abc.abstractmethod 

399 def encrypt(cls, key, keyusage, plaintext, confounder): 

400 # type: (Key, int, bytes, Optional[bytes]) -> bytes 

401 pass 

402 

403 @classmethod 

404 @abc.abstractmethod 

405 def decrypt(cls, key, keyusage, ciphertext): 

406 # type: (Key, int, bytes) -> bytes 

407 pass 

408 

409 @classmethod 

410 @abc.abstractmethod 

411 def prf(cls, key, string): 

412 # type: (Key, bytes) -> bytes 

413 pass 

414 

415 @classmethod 

416 @abc.abstractmethod 

417 def string_to_key(cls, string, salt, params): 

418 # type: (bytes, bytes, Optional[bytes]) -> Key 

419 pass 

420 

421 @classmethod 

422 def random_to_key(cls, seed): 

423 # type: (bytes) -> Key 

424 if len(seed) != cls.seedsize: 

425 raise ValueError("Wrong seed length") 

426 return Key(cls.etype, key=seed) 

427 

428 

429# RFC3961 sect 4 

430 

431 

432class _ChecksumProfile(object): 

433 """ 

434 Base class for checksum profiles. 

435 

436 Usable checksum classes must define: 

437 :func checksum: 

438 :attr macsize: Size of checksum in bytes 

439 :func verify: (if verification is not just checksum-and-compare) 

440 """ 

441 

442 macsize = None # type: int 

443 

444 @classmethod 

445 @abc.abstractmethod 

446 def checksum(cls, key, keyusage, text): 

447 # type: (Key, int, bytes) -> bytes 

448 pass 

449 

450 @classmethod 

451 def verify(cls, key, keyusage, text, cksum): 

452 # type: (Key, int, bytes, bytes) -> None 

453 expected = cls.checksum(key, keyusage, text) 

454 if not _mac_equal(cksum, expected): 

455 raise InvalidChecksum("checksum verification failure") 

456 

457 

458# RFC3961 sect 5.3 

459 

460 

461class _SimplifiedEncryptionProfile(_EncryptionAlgorithmProfile): 

462 """ 

463 Base class for etypes using the RFC 3961 simplified profile. 

464 Defines the encrypt, decrypt, and prf methods. 

465 

466 Subclasses must define: 

467 

468 :param blocksize: Underlying cipher block size in bytes 

469 :param padsize: Underlying cipher padding multiple (1 or blocksize) 

470 :param macsize: Size of integrity MAC in bytes 

471 :param hashmod: underlying hash function 

472 :param basic_encrypt, basic_decrypt: Underlying CBC/CTS cipher 

473 """ 

474 

475 blocksize = None # type: int 

476 padsize = None # type: int 

477 macsize = None # type: int 

478 hashmod = None # type: Any 

479 

480 # Used in RFC 8009. This is not a simplified profile per se but 

481 # is still pretty close. 

482 rfc8009 = False 

483 

484 @classmethod 

485 @abc.abstractmethod 

486 def basic_encrypt(cls, key, plaintext): 

487 # type: (bytes, bytes) -> bytes 

488 pass 

489 

490 @classmethod 

491 @abc.abstractmethod 

492 def basic_decrypt(cls, key, ciphertext): 

493 # type: (bytes, bytes) -> bytes 

494 pass 

495 

496 @classmethod 

497 def derive(cls, key, constant): 

498 # type: (Key, bytes) -> bytes 

499 """ 

500 Also known as "DK" in RFC3961. 

501 """ 

502 # RFC 3961 only says to n-fold the constant only if it is 

503 # shorter than the cipher block size. But all Unix 

504 # implementations n-fold constants if their length is larger 

505 # than the block size as well, and n-folding when the length 

506 # is equal to the block size is a no-op. 

507 plaintext = _n_fold(constant, cls.blocksize) 

508 rndseed = b"" 

509 while len(rndseed) < cls.seedsize: 

510 ciphertext = cls.basic_encrypt(key.key, plaintext) 

511 rndseed += ciphertext 

512 plaintext = ciphertext 

513 # DK(Key, Constant) = random-to-key(DR(Key, Constant)) 

514 return cls.random_to_key(rndseed[0 : cls.seedsize]).key 

515 

516 @classmethod 

517 def encrypt(cls, key, keyusage, plaintext, confounder, signtext=None): 

518 # type: (Key, int, bytes, Optional[bytes], Optional[bytes]) -> bytes 

519 """ 

520 Encryption function. 

521 

522 :param key: the key 

523 :param keyusage: the keyusage 

524 :param plaintext: the text to encrypt 

525 :param confounder: (optional) the confounder. If none, will be random 

526 :param signtext: (optional) make the checksum include different data than what 

527 is encrypted. Useful for kerberos GSS_WrapEx. If none, same as 

528 plaintext. 

529 """ 

530 if not cls.rfc8009: 

531 ki = cls.derive(key, struct.pack(">IB", keyusage, 0x55)) 

532 ke = cls.derive(key, struct.pack(">IB", keyusage, 0xAA)) 

533 else: 

534 ki = cls.derive(key, struct.pack(">IB", keyusage, 0x55), cls.macsize * 8) # type: ignore # noqa: E501 

535 ke = cls.derive(key, struct.pack(">IB", keyusage, 0xAA), cls.keysize * 8) # type: ignore # noqa: E501 

536 if confounder is None: 

537 confounder = os.urandom(cls.blocksize) 

538 basic_plaintext = confounder + _zeropad(plaintext, cls.padsize) 

539 if signtext is None: 

540 signtext = basic_plaintext 

541 if not cls.rfc8009: 

542 # Simplified profile 

543 hmac = Hmac(ki, cls.hashmod).digest(signtext) 

544 return cls.basic_encrypt(ke, basic_plaintext) + hmac[: cls.macsize] 

545 else: 

546 # RFC 8009 

547 C = cls.basic_encrypt(ke, basic_plaintext) 

548 hmac = Hmac(ki, cls.hashmod).digest(b"\0" * 16 + C) # XXX IV 

549 return C + hmac[: cls.macsize] 

550 

551 @classmethod 

552 def decrypt(cls, key, keyusage, ciphertext, presignfunc=None): 

553 # type: (Key, int, bytes, Optional[Callable[[bytes, bytes], bytes]]) -> bytes 

554 """ 

555 decryption function 

556 """ 

557 if not cls.rfc8009: 

558 ki = cls.derive(key, struct.pack(">IB", keyusage, 0x55)) 

559 ke = cls.derive(key, struct.pack(">IB", keyusage, 0xAA)) 

560 else: 

561 ki = cls.derive(key, struct.pack(">IB", keyusage, 0x55), cls.macsize * 8) # type: ignore # noqa: E501 

562 ke = cls.derive(key, struct.pack(">IB", keyusage, 0xAA), cls.keysize * 8) # type: ignore # noqa: E501 

563 if len(ciphertext) < cls.blocksize + cls.macsize: 

564 raise ValueError("Ciphertext too short") 

565 basic_ctext, mac = ciphertext[: -cls.macsize], ciphertext[-cls.macsize :] 

566 if len(basic_ctext) % cls.padsize != 0: 

567 raise ValueError("ciphertext does not meet padding requirement") 

568 if not cls.rfc8009: 

569 # Simplified profile 

570 basic_plaintext = cls.basic_decrypt(ke, basic_ctext) 

571 signtext = basic_plaintext 

572 if presignfunc: 

573 # Allow to have additional processing of the data that is to be signed. 

574 # This is useful for GSS_WrapEx 

575 signtext = presignfunc( 

576 basic_plaintext[: cls.blocksize], 

577 basic_plaintext[cls.blocksize :], 

578 ) 

579 hmac = Hmac(ki, cls.hashmod).digest(signtext) 

580 expmac = hmac[: cls.macsize] 

581 if not _mac_equal(mac, expmac): 

582 raise ValueError("ciphertext integrity failure") 

583 else: 

584 # RFC 8009 

585 signtext = b"\0" * 16 + basic_ctext # XXX IV 

586 if presignfunc: 

587 # Allow to have additional processing of the data that is to be signed. 

588 # This is useful for GSS_WrapEx 

589 signtext = presignfunc( 

590 basic_ctext[16 : 16 + cls.blocksize], 

591 basic_ctext[16 + cls.blocksize :], 

592 ) 

593 hmac = Hmac(ki, cls.hashmod).digest(signtext) 

594 expmac = hmac[: cls.macsize] 

595 if not _mac_equal(mac, expmac): 

596 raise ValueError("ciphertext integrity failure") 

597 basic_plaintext = cls.basic_decrypt(ke, basic_ctext) 

598 # Discard the confounder. 

599 return bytes(basic_plaintext[cls.blocksize :]) 

600 

601 @classmethod 

602 def prf(cls, key, string): 

603 # type: (Key, bytes) -> bytes 

604 """ 

605 pseudo-random function 

606 """ 

607 # Hash the input. RFC 3961 says to truncate to the padding 

608 # size, but implementations truncate to the block size. 

609 hashval = cls.hashmod().digest(string) 

610 if len(hashval) % cls.blocksize: 

611 hashval = hashval[: -(len(hashval) % cls.blocksize)] 

612 # Encrypt the hash with a derived key. 

613 kp = cls.derive(key, b"prf") 

614 return cls.basic_encrypt(kp, hashval) 

615 

616 

617# RFC3961 sect 5.4 

618 

619 

620class _SimplifiedChecksum(_ChecksumProfile): 

621 """ 

622 Base class for checksums using the RFC 3961 simplified profile. 

623 Defines the checksum and verify methods. 

624 

625 Subclasses must define: 

626 :attr enc: Profile of associated etype 

627 """ 

628 

629 enc = None # type: Type[_SimplifiedEncryptionProfile] 

630 

631 # Used in RFC 8009. This is not a simplified profile per se but 

632 # is still pretty close. 

633 rfc8009 = False 

634 

635 @classmethod 

636 def checksum(cls, key, keyusage, text): 

637 # type: (Key, int, bytes) -> bytes 

638 if not cls.rfc8009: 

639 # Simplified profile 

640 kc = cls.enc.derive(key, struct.pack(">IB", keyusage, 0x99)) 

641 else: 

642 # RFC 8009 

643 kc = cls.enc.derive( # type: ignore 

644 key, struct.pack(">IB", keyusage, 0x99), cls.macsize * 8 

645 ) 

646 hmac = Hmac(kc, cls.enc.hashmod).digest(text) 

647 return hmac[: cls.macsize] 

648 

649 @classmethod 

650 def verify(cls, key, keyusage, text, cksum): 

651 # type: (Key, int, bytes, bytes) -> None 

652 if key.etype != cls.enc.etype: 

653 raise ValueError("Wrong key type for checksum") 

654 super(_SimplifiedChecksum, cls).verify(key, keyusage, text, cksum) 

655 

656 

657# RFC3961 sect 6.1 

658 

659 

660class _CRC32(_ChecksumProfile): 

661 macsize = 4 

662 

663 # This isn't your usual CRC32, it's a "modified version" according to the RFC3961. 

664 # Another RFC states it's just a buggy version of the actual CRC32. 

665 

666 @classmethod 

667 def checksum(cls, key, keyusage, text): 

668 # type: (Optional[Key], int, bytes) -> bytes 

669 c = 0 

670 for i in range(len(text)): 

671 idx = text[i] ^ c 

672 idx &= 0xFF 

673 c >>= 8 

674 c ^= CRC32_TABLE[idx] 

675 return c.to_bytes(4, "little") 

676 

677 

678# RFC3961 sect 6.2 

679 

680 

681class _DESCBC(_SimplifiedEncryptionProfile): 

682 keysize = 8 

683 seedsize = 8 

684 blocksize = 8 

685 padsize = 8 

686 macsize = 16 

687 hashmod = Hash_MD5 

688 

689 @classmethod 

690 def encrypt(cls, key, keyusage, plaintext, confounder, signtext=None): 

691 # type: (Key, int, bytes, Optional[bytes], Any) -> bytes 

692 if confounder is None: 

693 confounder = os.urandom(cls.blocksize) 

694 basic_plaintext = ( 

695 confounder + b"\x00" * cls.macsize + _zeropad(plaintext, cls.padsize) 

696 ) 

697 checksum = cls.hashmod().digest(basic_plaintext) 

698 basic_plaintext = ( 

699 basic_plaintext[: len(confounder)] 

700 + checksum 

701 + basic_plaintext[len(confounder) + len(checksum) :] 

702 ) 

703 return cls.basic_encrypt(key.key, basic_plaintext) 

704 

705 @classmethod 

706 def decrypt(cls, key, keyusage, ciphertext, presignfunc=None): 

707 # type: (Key, int, bytes, Any) -> bytes 

708 if len(ciphertext) < cls.blocksize + cls.macsize: 

709 raise ValueError("ciphertext too short") 

710 

711 complex_plaintext = cls.basic_decrypt(key.key, ciphertext) 

712 cofounder = complex_plaintext[: cls.padsize] 

713 mac = complex_plaintext[cls.padsize : cls.padsize + cls.macsize] 

714 message = complex_plaintext[cls.padsize + cls.macsize :] 

715 

716 expmac = cls.hashmod().digest(cofounder + b"\x00" * cls.macsize + message) 

717 if not _mac_equal(mac, expmac): 

718 raise InvalidChecksum("ciphertext integrity failure") 

719 return bytes(message) 

720 

721 @classmethod 

722 def mit_des_string_to_key(cls, string, salt): 

723 # type: (bytes, bytes) -> Key 

724 def fixparity(deskey): 

725 # type: (List[int]) -> bytes 

726 temp = b"" 

727 for i in range(len(deskey)): 

728 t = (bin(orb(deskey[i]))[2:]).rjust(8, "0") 

729 if t[:7].count("1") % 2 == 0: 

730 temp += chb(int(t[:7] + "1", 2)) 

731 else: 

732 temp += chb(int(t[:7] + "0", 2)) 

733 return temp 

734 

735 def addparity(l1): 

736 # type: (List[int]) -> List[int] 

737 temp = list() 

738 for byte in l1: 

739 if (bin(byte).count("1") % 2) == 0: 

740 byte = (byte << 1) | 0b00000001 

741 else: 

742 byte = (byte << 1) & 0b11111110 

743 temp.append(byte) 

744 return temp 

745 

746 def XOR(l1, l2): 

747 # type: (List[int], List[int]) -> List[int] 

748 temp = list() 

749 for b1, b2 in zip(l1, l2): 

750 temp.append((b1 ^ b2) & 0b01111111) 

751 

752 return temp 

753 

754 odd = True 

755 tempstring = [0, 0, 0, 0, 0, 0, 0, 0] 

756 s = _zeropad(string + salt, cls.padsize) 

757 

758 for block in [s[i : i + 8] for i in range(0, len(s), 8)]: 

759 temp56 = list() 

760 # removeMSBits 

761 for byte in block: 

762 temp56.append(orb(byte) & 0b01111111) 

763 

764 # reverse 

765 if odd is False: 

766 bintemp = b"" 

767 for byte in temp56: 

768 bintemp += bin(byte)[2:].rjust(7, "0").encode() 

769 bintemp = bintemp[::-1] 

770 

771 temp56 = list() 

772 for bits7 in [bintemp[i : i + 7] for i in range(0, len(bintemp), 7)]: 

773 temp56.append(int(bits7, 2)) 

774 

775 odd = not odd 

776 tempstring = XOR(tempstring, temp56) 

777 

778 tempkey = bytearray(b"".join(chb(byte) for byte in addparity(tempstring))) 

779 if bytes(tempkey) in WEAK_DES_KEYS: 

780 tempkey[7] = tempkey[7] ^ 0xF0 

781 

782 tempkeyb = bytes(tempkey) 

783 des = Cipher(DES(tempkeyb), modes.CBC(tempkeyb)).encryptor() 

784 chekcsumkey = des.update(s)[-8:] 

785 chekcsumkey = bytearray(fixparity(chekcsumkey)) 

786 if bytes(chekcsumkey) in WEAK_DES_KEYS: 

787 chekcsumkey[7] = chekcsumkey[7] ^ 0xF0 

788 

789 return Key(cls.etype, key=bytes(chekcsumkey)) 

790 

791 @classmethod 

792 def basic_encrypt(cls, key, plaintext): 

793 # type: (bytes, bytes) -> bytes 

794 assert len(plaintext) % 8 == 0 

795 des = Cipher(DES(key), modes.CBC(b"\0" * 8)).encryptor() 

796 return des.update(bytes(plaintext)) 

797 

798 @classmethod 

799 def basic_decrypt(cls, key, ciphertext): 

800 # type: (bytes, bytes) -> bytes 

801 assert len(ciphertext) % 8 == 0 

802 des = Cipher(DES(key), modes.CBC(b"\0" * 8)).decryptor() 

803 return des.update(bytes(ciphertext)) 

804 

805 @classmethod 

806 def string_to_key(cls, string, salt, params): 

807 # type: (bytes, bytes, Optional[bytes]) -> Key 

808 if params is not None and params != b"": 

809 raise ValueError("Invalid DES string-to-key parameters") 

810 key = cls.mit_des_string_to_key(string, salt) 

811 return key 

812 

813 

814# RFC3961 sect 6.2.1 

815 

816 

817class _DESMD5(_DESCBC): 

818 etype = EncryptionType.DES_CBC_MD5 

819 hashmod = Hash_MD5 

820 reqcksum = ChecksumType.RSA_MD5_DES 

821 

822 

823# RFC3961 sect 6.2.2 

824 

825 

826class _DESMD4(_DESCBC): 

827 etype = EncryptionType.DES_CBC_MD4 

828 hashmod = Hash_MD4 

829 reqcksum = ChecksumType.RSA_MD4_DES 

830 

831 

832# RFC3961 sect 6.3 

833 

834 

835class _DES3CBC(_SimplifiedEncryptionProfile): 

836 etype = EncryptionType.DES3_CBC_SHA1_KD 

837 keysize = 24 

838 seedsize = 21 

839 blocksize = 8 

840 padsize = 8 

841 macsize = 20 

842 hashmod = Hash_SHA 

843 reqcksum = ChecksumType.HMAC_SHA1_DES3_KD 

844 

845 @classmethod 

846 def random_to_key(cls, seed): 

847 # type: (bytes) -> Key 

848 # XXX Maybe reframe as _DESEncryptionType.random_to_key and use that 

849 # way from DES3 random-to-key when DES is implemented, since 

850 # MIT does this instead of the RFC 3961 random-to-key. 

851 def expand(seed): 

852 # type: (bytes) -> bytes 

853 def parity(b): 

854 # type: (int) -> int 

855 # Return b with the low-order bit set to yield odd parity. 

856 b &= ~1 

857 return b if bin(b & ~1).count("1") % 2 else b | 1 

858 

859 assert len(seed) == 7 

860 firstbytes = [parity(b & ~1) for b in seed] 

861 lastbyte = parity(sum((seed[i] & 1) << i + 1 for i in range(7))) 

862 keybytes = bytearray(firstbytes + [lastbyte]) 

863 if bytes(keybytes) in WEAK_DES_KEYS: 

864 keybytes[7] = keybytes[7] ^ 0xF0 

865 return bytes(keybytes) 

866 

867 if len(seed) != 21: 

868 raise ValueError("Wrong seed length") 

869 k1, k2, k3 = expand(seed[:7]), expand(seed[7:14]), expand(seed[14:]) 

870 return Key(cls.etype, key=k1 + k2 + k3) 

871 

872 @classmethod 

873 def string_to_key(cls, string, salt, params): 

874 # type: (bytes, bytes, Optional[bytes]) -> Key 

875 if params is not None and params != b"": 

876 raise ValueError("Invalid DES3 string-to-key parameters") 

877 k = cls.random_to_key(_n_fold(string + salt, 21)) 

878 return Key( 

879 cls.etype, 

880 key=cls.derive(k, b"kerberos"), 

881 ) 

882 

883 @classmethod 

884 def basic_encrypt(cls, key, plaintext): 

885 # type: (bytes, bytes) -> bytes 

886 assert len(plaintext) % 8 == 0 

887 des3 = Cipher( 

888 decrepit_algorithms.TripleDES(key), modes.CBC(b"\0" * 8) 

889 ).encryptor() 

890 return des3.update(bytes(plaintext)) 

891 

892 @classmethod 

893 def basic_decrypt(cls, key, ciphertext): 

894 # type: (bytes, bytes) -> bytes 

895 assert len(ciphertext) % 8 == 0 

896 des3 = Cipher( 

897 decrepit_algorithms.TripleDES(key), modes.CBC(b"\0" * 8) 

898 ).decryptor() 

899 return des3.update(bytes(ciphertext)) 

900 

901 

902class _SHA1DES3(_SimplifiedChecksum): 

903 macsize = 20 

904 enc = _DES3CBC 

905 

906 

907############ 

908# RFC 3962 # 

909############ 

910 

911 

912# RFC3962 sect 6 

913 

914 

915class _AESEncryptionType_SHA1_96(_SimplifiedEncryptionProfile, abc.ABCMeta): 

916 blocksize = 16 

917 padsize = 1 

918 macsize = 12 

919 hashmod = Hash_SHA 

920 

921 @classmethod 

922 def string_to_key(cls, string, salt, params): 

923 # type: (bytes, bytes, Optional[bytes]) -> Key 

924 iterations = struct.unpack(">L", params or b"\x00\x00\x10\x00")[0] 

925 kdf = PBKDF2HMAC( 

926 algorithm=hashes.SHA1(), 

927 length=cls.seedsize, 

928 salt=salt, 

929 iterations=iterations, 

930 ) 

931 tkey = cls.random_to_key(kdf.derive(string)) 

932 return Key( 

933 cls.etype, 

934 key=cls.derive(tkey, b"kerberos"), 

935 ) 

936 

937 # basic_encrypt and basic_decrypt implement AES in CBC-CS3 mode 

938 

939 @classmethod 

940 def basic_encrypt(cls, key, plaintext): 

941 # type: (bytes, bytes) -> bytes 

942 assert len(plaintext) >= 16 

943 aes = Cipher(algorithms.AES(key), modes.CBC(b"\0" * 16)).encryptor() 

944 ctext = aes.update(_zeropad(bytes(plaintext), 16)) 

945 if len(plaintext) > 16: 

946 # Swap the last two ciphertext blocks and truncate the 

947 # final block to match the plaintext length. 

948 lastlen = len(plaintext) % 16 or 16 

949 ctext = ctext[:-32] + ctext[-16:] + ctext[-32:-16][:lastlen] 

950 return ctext 

951 

952 @classmethod 

953 def basic_decrypt(cls, key, ciphertext): 

954 # type: (bytes, bytes) -> bytes 

955 assert len(ciphertext) >= 16 

956 aes = Cipher(algorithms.AES(key), modes.ECB()).decryptor() 

957 if len(ciphertext) == 16: 

958 return aes.update(ciphertext) 

959 # Split the ciphertext into blocks. The last block may be partial. 

960 cblocks = [ 

961 bytearray(ciphertext[p : p + 16]) for p in range(0, len(ciphertext), 16) 

962 ] 

963 lastlen = len(cblocks[-1]) 

964 # CBC-decrypt all but the last two blocks. 

965 prev_cblock = bytearray(16) 

966 plaintext = b"" 

967 for bb in cblocks[:-2]: 

968 plaintext += _xorbytes(bytearray(aes.update(bytes(bb))), prev_cblock) 

969 prev_cblock = bb 

970 # Decrypt the second-to-last cipher block. The left side of 

971 # the decrypted block will be the final block of plaintext 

972 # xor'd with the final partial cipher block; the right side 

973 # will be the omitted bytes of ciphertext from the final 

974 # block. 

975 bb = bytearray(aes.update(bytes(cblocks[-2]))) 

976 lastplaintext = _xorbytes(bb[:lastlen], cblocks[-1]) 

977 omitted = bb[lastlen:] 

978 # Decrypt the final cipher block plus the omitted bytes to get 

979 # the second-to-last plaintext block. 

980 plaintext += _xorbytes( 

981 bytearray(aes.update(bytes(cblocks[-1]) + bytes(omitted))), prev_cblock 

982 ) 

983 return plaintext + lastplaintext 

984 

985 

986# RFC3962 sect 7 

987 

988 

989class _AES128CTS_SHA1_96(_AESEncryptionType_SHA1_96): 

990 etype = EncryptionType.AES128_CTS_HMAC_SHA1_96 

991 keysize = 16 

992 seedsize = 16 

993 reqcksum = ChecksumType.HMAC_SHA1_96_AES128 

994 

995 

996class _AES256CTS_SHA1_96(_AESEncryptionType_SHA1_96): 

997 etype = EncryptionType.AES256_CTS_HMAC_SHA1_96 

998 keysize = 32 

999 seedsize = 32 

1000 reqcksum = ChecksumType.HMAC_SHA1_96_AES256 

1001 

1002 

1003class _SHA1_96_AES128(_SimplifiedChecksum): 

1004 macsize = 12 

1005 enc = _AES128CTS_SHA1_96 

1006 

1007 

1008class _SHA1_96_AES256(_SimplifiedChecksum): 

1009 macsize = 12 

1010 enc = _AES256CTS_SHA1_96 

1011 

1012 

1013############ 

1014# RFC 4757 # 

1015############ 

1016 

1017# RFC4757 sect 4 

1018 

1019 

1020class _HMACMD5(_ChecksumProfile): 

1021 macsize = 16 

1022 

1023 @classmethod 

1024 def checksum(cls, key, keyusage, text): 

1025 # type: (Key, int, bytes) -> bytes 

1026 ksign = Hmac_MD5(key.key).digest(b"signaturekey\0") 

1027 md5hash = Hash_MD5().digest(_RC4.usage_str(keyusage) + text) 

1028 return Hmac_MD5(ksign).digest(md5hash) 

1029 

1030 @classmethod 

1031 def verify(cls, key, keyusage, text, cksum): 

1032 # type: (Key, int, bytes, bytes) -> None 

1033 if key.etype not in [EncryptionType.RC4_HMAC, EncryptionType.RC4_HMAC_EXP]: 

1034 raise ValueError("Wrong key type for checksum") 

1035 super(_HMACMD5, cls).verify(key, keyusage, text, cksum) 

1036 

1037 

1038# RFC4757 sect 5 

1039 

1040 

1041class _RC4(_EncryptionAlgorithmProfile): 

1042 etype = EncryptionType.RC4_HMAC 

1043 keysize = 16 

1044 seedsize = 16 

1045 reqcksum = ChecksumType.HMAC_MD5 

1046 export = False 

1047 

1048 @staticmethod 

1049 def usage_str(keyusage): 

1050 # type: (int) -> bytes 

1051 # Return a four-byte string for an RFC 3961 keyusage, using 

1052 # the RFC 4757 rules sect 3. Per the errata, do not map 9 to 8. 

1053 table = {3: 8, 23: 13} 

1054 msusage = table[keyusage] if keyusage in table else keyusage 

1055 return struct.pack("<I", msusage) 

1056 

1057 @classmethod 

1058 def string_to_key(cls, string, salt, params): 

1059 # type: (bytes, bytes, Optional[bytes]) -> Key 

1060 if params is not None and params != b"": 

1061 raise ValueError("Invalid RC4 string-to-key parameters") 

1062 utf16string = plain_str(string).encode("UTF-16LE") 

1063 return Key(cls.etype, key=Hash_MD4().digest(utf16string)) 

1064 

1065 @classmethod 

1066 def encrypt(cls, key, keyusage, plaintext, confounder): 

1067 # type: (Key, int, bytes, Optional[bytes]) -> bytes 

1068 if confounder is None: 

1069 confounder = os.urandom(8) 

1070 if cls.export: 

1071 ki = Hmac_MD5(key.key).digest(b"fortybits\x00" + cls.usage_str(keyusage)) 

1072 else: 

1073 ki = Hmac_MD5(key.key).digest(cls.usage_str(keyusage)) 

1074 cksum = Hmac_MD5(ki).digest(confounder + plaintext) 

1075 if cls.export: 

1076 ki = ki[:7] + b"\xab" * 9 

1077 ke = Hmac_MD5(ki).digest(cksum) 

1078 rc4 = Cipher(algorithms.ARC4(ke), mode=None).encryptor() 

1079 return cksum + rc4.update(bytes(confounder + plaintext)) 

1080 

1081 @classmethod 

1082 def decrypt(cls, key, keyusage, ciphertext): 

1083 # type: (Key, int, bytes) -> bytes 

1084 if len(ciphertext) < 24: 

1085 raise ValueError("ciphertext too short") 

1086 cksum, basic_ctext = ciphertext[:16], ciphertext[16:] 

1087 if cls.export: 

1088 ki = Hmac_MD5(key.key).digest(b"fortybits\x00" + cls.usage_str(keyusage)) 

1089 else: 

1090 ki = Hmac_MD5(key.key).digest(cls.usage_str(keyusage)) 

1091 if cls.export: 

1092 kie = ki[:7] + b"\xab" * 9 

1093 else: 

1094 kie = ki 

1095 ke = Hmac_MD5(kie).digest(cksum) 

1096 rc4 = Cipher(decrepit_algorithms.ARC4(ke), mode=None).decryptor() 

1097 basic_plaintext = rc4.update(bytes(basic_ctext)) 

1098 exp_cksum = Hmac_MD5(ki).digest(basic_plaintext) 

1099 ok = _mac_equal(cksum, exp_cksum) 

1100 if not ok and keyusage == 9: 

1101 # Try again with usage 8, due to RFC 4757 errata. 

1102 ki = Hmac_MD5(key.key).digest(struct.pack("<I", 8)) 

1103 exp_cksum = Hmac_MD5(ki).digest(basic_plaintext) 

1104 ok = _mac_equal(cksum, exp_cksum) 

1105 if not ok: 

1106 raise InvalidChecksum("ciphertext integrity failure") 

1107 # Discard the confounder. 

1108 return bytes(basic_plaintext[8:]) 

1109 

1110 @classmethod 

1111 def prf(cls, key, string): 

1112 # type: (Key, bytes) -> bytes 

1113 return Hmac_SHA(key.key).digest(string) 

1114 

1115 

1116class _RC4_EXPORT(_RC4): 

1117 etype = EncryptionType.RC4_HMAC_EXP 

1118 export = True 

1119 

1120 

1121############ 

1122# RFC 8009 # 

1123############ 

1124 

1125 

1126class _AESEncryptionType_SHA256_SHA384(_AESEncryptionType_SHA1_96, abc.ABCMeta): 

1127 enctypename = None # type: bytes 

1128 hashmod: _GenericHash = None # Scapy 

1129 _hashmod: hashes.HashAlgorithm = None # Cryptography 

1130 

1131 # Turn on RFC 8009 mode 

1132 rfc8009 = True 

1133 

1134 @classmethod 

1135 def derive(cls, key, label, k, context=b""): # type: ignore 

1136 # type: (Key, bytes, int, bytes) -> bytes 

1137 """ 

1138 Also known as "KDF-HMAC-SHA2" in RFC8009. 

1139 """ 

1140 # RFC 8009 sect 3 

1141 return SP800108_KDFCTR( 

1142 K_I=key.key, 

1143 Label=label, 

1144 Context=context, 

1145 L=k, 

1146 hashmod=cls.hashmod, 

1147 ) 

1148 

1149 @classmethod 

1150 def string_to_key(cls, string, salt, params): 

1151 # type: (bytes, bytes, Optional[bytes]) -> Key 

1152 # RFC 8009 sect 4 

1153 iterations = struct.unpack(">L", params or b"\x00\x00\x80\x00")[0] 

1154 saltp = cls.enctypename + b"\x00" + salt 

1155 kdf = PBKDF2HMAC( 

1156 algorithm=cls._hashmod(), 

1157 length=cls.seedsize, 

1158 salt=saltp, 

1159 iterations=iterations, 

1160 ) 

1161 tkey = cls.random_to_key(kdf.derive(string)) 

1162 return Key( 

1163 cls.etype, 

1164 key=cls.derive(tkey, b"kerberos", cls.keysize * 8), 

1165 ) 

1166 

1167 @classmethod 

1168 def prf(cls, key, string): 

1169 # type: (Key, bytes) -> bytes 

1170 return cls.derive(key, b"prf", cls.hashmod.hash_len * 8, string) 

1171 

1172 

1173class _AES128CTS_SHA256_128(_AESEncryptionType_SHA256_SHA384): 

1174 etype = EncryptionType.AES128_CTS_HMAC_SHA256_128 

1175 keysize = 16 

1176 seedsize = 16 

1177 macsize = 16 

1178 reqcksum = ChecksumType.HMAC_SHA256_128_AES128 

1179 # _AESEncryptionType_SHA256_SHA384 parameters 

1180 enctypename = b"aes128-cts-hmac-sha256-128" 

1181 hashmod = Hash_SHA256 

1182 _hashmod = hashes.SHA256 

1183 

1184 

1185class _AES256CTS_SHA384_192(_AESEncryptionType_SHA256_SHA384): 

1186 etype = EncryptionType.AES256_CTS_HMAC_SHA384_192 

1187 keysize = 32 

1188 seedsize = 32 

1189 macsize = 24 

1190 reqcksum = ChecksumType.HMAC_SHA384_192_AES256 

1191 # _AESEncryptionType_SHA256_SHA384 parameters 

1192 enctypename = b"aes256-cts-hmac-sha384-192" 

1193 hashmod = Hash_SHA384 

1194 _hashmod = hashes.SHA384 

1195 

1196 

1197class _SHA256_128_AES128(_SimplifiedChecksum): 

1198 macsize = 16 

1199 enc = _AES128CTS_SHA256_128 

1200 rfc8009 = True 

1201 

1202 

1203class _SHA384_182_AES256(_SimplifiedChecksum): 

1204 macsize = 24 

1205 enc = _AES256CTS_SHA384_192 

1206 rfc8009 = True 

1207 

1208 

1209############## 

1210# Key object # 

1211############## 

1212 

1213_enctypes = { 

1214 # DES_CBC_CRC - UNIMPLEMENTED 

1215 EncryptionType.DES_CBC_MD5: _DESMD5, 

1216 EncryptionType.DES_CBC_MD4: _DESMD4, 

1217 # DES3_CBC_SHA1 - UNIMPLEMENTED 

1218 EncryptionType.DES3_CBC_SHA1_KD: _DES3CBC, 

1219 EncryptionType.AES128_CTS_HMAC_SHA1_96: _AES128CTS_SHA1_96, 

1220 EncryptionType.AES256_CTS_HMAC_SHA1_96: _AES256CTS_SHA1_96, 

1221 EncryptionType.AES128_CTS_HMAC_SHA256_128: _AES128CTS_SHA256_128, 

1222 EncryptionType.AES256_CTS_HMAC_SHA384_192: _AES256CTS_SHA384_192, 

1223 # CAMELLIA128-CTS-CMAC - UNIMPLEMENTED 

1224 # CAMELLIA256-CTS-CMAC - UNIMPLEMENTED 

1225 EncryptionType.RC4_HMAC: _RC4, 

1226 EncryptionType.RC4_HMAC_EXP: _RC4_EXPORT, 

1227} 

1228 

1229 

1230_checksums = { 

1231 ChecksumType.CRC32: _CRC32, 

1232 # RSA_MD4 - UNIMPLEMENTED 

1233 # RSA_MD4_DES - UNIMPLEMENTED 

1234 # RSA_MD5 - UNIMPLEMENTED 

1235 # RSA_MD5_DES - UNIMPLEMENTED 

1236 # SHA1 - UNIMPLEMENTED 

1237 ChecksumType.HMAC_SHA1_DES3_KD: _SHA1DES3, 

1238 # HMAC_SHA1_DES3 - UNIMPLEMENTED 

1239 ChecksumType.HMAC_SHA1_96_AES128: _SHA1_96_AES128, 

1240 ChecksumType.HMAC_SHA1_96_AES256: _SHA1_96_AES256, 

1241 # CMAC-CAMELLIA128 - UNIMPLEMENTED 

1242 # CMAC-CAMELLIA256 - UNIMPLEMENTED 

1243 ChecksumType.HMAC_SHA256_128_AES128: _SHA256_128_AES128, 

1244 ChecksumType.HMAC_SHA384_192_AES256: _SHA384_182_AES256, 

1245 ChecksumType.HMAC_MD5: _HMACMD5, 

1246 0xFFFFFF76: _HMACMD5, 

1247} 

1248 

1249 

1250class Key(object): 

1251 def __init__( 

1252 self, 

1253 etype: Union[EncryptionType, int, None] = None, 

1254 key: bytes = b"", 

1255 cksumtype: Union[ChecksumType, int, None] = None, 

1256 ) -> None: 

1257 """ 

1258 Kerberos Key object. 

1259 

1260 :param etype: the EncryptionType 

1261 :param cksumtype: the ChecksumType 

1262 :param key: the bytes containing the key bytes for this Key. 

1263 """ 

1264 assert etype or cksumtype, "Provide an etype or a cksumtype !" 

1265 assert key, "Provide a key !" 

1266 if isinstance(etype, int): 

1267 etype = EncryptionType(etype) 

1268 if isinstance(cksumtype, int): 

1269 cksumtype = ChecksumType(cksumtype) 

1270 self.etype = etype 

1271 if etype is not None: 

1272 try: 

1273 self.ep = _enctypes[etype] 

1274 except ValueError: 

1275 raise ValueError("UNKNOWN/UNIMPLEMENTED etype '%s'" % etype) 

1276 if len(key) != self.ep.keysize: 

1277 raise ValueError( 

1278 "Wrong key length. Got %s. Expected %s" 

1279 % (len(key), self.ep.keysize) 

1280 ) 

1281 if cksumtype is None and self.ep.reqcksum in _checksums: 

1282 cksumtype = self.ep.reqcksum 

1283 self.cksumtype = cksumtype 

1284 if cksumtype is not None: 

1285 try: 

1286 self.cp = _checksums[cksumtype] 

1287 except ValueError: 

1288 raise ValueError("UNKNOWN/UNIMPLEMENTED cksumtype '%s'" % cksumtype) 

1289 if self.etype is None and issubclass(self.cp, _SimplifiedChecksum): 

1290 self.etype = self.cp.enc.etype # type: ignore 

1291 self.key = key 

1292 

1293 def __repr__(self): 

1294 # type: () -> str 

1295 if self.etype: 

1296 name = self.etype.name 

1297 elif self.cksumtype: 

1298 name = self.cksumtype.name 

1299 else: 

1300 return "<Key UNKNOWN>" 

1301 return "<Key %s%s>" % ( 

1302 name, 

1303 " (%s octets)" % len(self.key), 

1304 ) 

1305 

1306 def encrypt(self, keyusage, plaintext, confounder=None, **kwargs): 

1307 # type: (int, bytes, Optional[bytes], **Any) -> bytes 

1308 """ 

1309 Encrypt data using the current Key. 

1310 

1311 :param keyusage: the key usage 

1312 :param plaintext: the plain text to encrypt 

1313 :param confounder: (optional) choose the confounder. Otherwise random. 

1314 """ 

1315 return self.ep.encrypt(self, keyusage, bytes(plaintext), confounder, **kwargs) 

1316 

1317 def decrypt(self, keyusage, ciphertext, **kwargs): 

1318 # type: (int, bytes, **Any) -> bytes 

1319 """ 

1320 Decrypt data using the current Key. 

1321 

1322 :param keyusage: the key usage 

1323 :param ciphertext: the encrypted text to decrypt 

1324 """ 

1325 # Throw InvalidChecksum on checksum failure. Throw ValueError on 

1326 # invalid key enctype or malformed ciphertext. 

1327 return self.ep.decrypt(self, keyusage, ciphertext, **kwargs) 

1328 

1329 def prf(self, string): 

1330 # type: (bytes) -> bytes 

1331 return self.ep.prf(self, string) 

1332 

1333 def make_checksum(self, keyusage, text, cksumtype=None, **kwargs): 

1334 # type: (int, bytes, Optional[int], **Any) -> bytes 

1335 """ 

1336 Create a checksum using the current Key. 

1337 

1338 :param keyusage: the key usage 

1339 :param text: the text to create a checksum from 

1340 :param cksumtype: (optional) override the checksum type 

1341 """ 

1342 if cksumtype is not None and cksumtype != self.cksumtype: 

1343 # Clone key and use a different cksumtype 

1344 return Key( 

1345 cksumtype=cksumtype, 

1346 key=self.key, 

1347 ).make_checksum(keyusage=keyusage, text=text, **kwargs) 

1348 if self.cksumtype is None: 

1349 raise ValueError("cksumtype not specified !") 

1350 return self.cp.checksum(self, keyusage, text, **kwargs) 

1351 

1352 def verify_checksum(self, keyusage, text, cksum, cksumtype=None): 

1353 # type: (int, bytes, bytes, Optional[int]) -> None 

1354 """ 

1355 Verify a checksum using the current Key. 

1356 

1357 :param keyusage: the key usage 

1358 :param text: the text to verify 

1359 :param cksum: the expected checksum 

1360 :param cksumtype: (optional) override the checksum type 

1361 """ 

1362 if cksumtype is not None and cksumtype != self.cksumtype: 

1363 # Clone key and use a different cksumtype 

1364 return Key( 

1365 cksumtype=cksumtype, 

1366 key=self.key, 

1367 ).verify_checksum(keyusage=keyusage, text=text, cksum=cksum) 

1368 # Throw InvalidChecksum exception on checksum failure. Throw 

1369 # ValueError on invalid cksumtype, invalid key enctype, or 

1370 # malformed checksum. 

1371 if self.cksumtype is None: 

1372 raise ValueError("cksumtype not specified !") 

1373 self.cp.verify(self, keyusage, text, cksum) 

1374 

1375 @classmethod 

1376 def random_to_key(cls, etype, seed): 

1377 # type: (EncryptionType, bytes) -> Key 

1378 """ 

1379 random-to-key per RFC3961 

1380 

1381 This is used to create a random Key from a seed. 

1382 """ 

1383 try: 

1384 ep = _enctypes[etype] 

1385 except ValueError: 

1386 raise ValueError("Unknown etype '%s'" % etype) 

1387 if len(seed) != ep.seedsize: 

1388 raise ValueError("Wrong crypto seed length") 

1389 return ep.random_to_key(seed) 

1390 

1391 @classmethod 

1392 def new_random_key(cls, etype): 

1393 # type: (EncryptionType) -> Key 

1394 """ 

1395 Generates a seed then calls random-to-key 

1396 """ 

1397 try: 

1398 ep = _enctypes[etype] 

1399 except ValueError: 

1400 raise ValueError("Unknown etype '%s'" % etype) 

1401 return cls.random_to_key(etype, os.urandom(ep.seedsize)) 

1402 

1403 @classmethod 

1404 def string_to_key(cls, etype, string, salt, params=None): 

1405 # type: (EncryptionType, bytes, bytes, Optional[bytes]) -> Key 

1406 """ 

1407 string-to-key per RFC3961 

1408 

1409 This is typically used to create a Key object from a password + salt 

1410 """ 

1411 try: 

1412 ep = _enctypes[etype] 

1413 except ValueError: 

1414 raise ValueError("Unknown etype '%s'" % etype) 

1415 return ep.string_to_key(string, salt, params) 

1416 

1417 

1418############ 

1419# RFC 6113 # 

1420############ 

1421 

1422 

1423def KRB_FX_CF2(key1, key2, pepper1, pepper2): 

1424 # type: (Key, Key, bytes, bytes) -> Key 

1425 """ 

1426 KRB-FX-CF2 RFC6113 

1427 """ 

1428 

1429 def prfplus(key, pepper): 

1430 # type: (Key, bytes) -> bytes 

1431 # Produce l bytes of output using the RFC 6113 PRF+ function. 

1432 out = b"" 

1433 count = 1 

1434 while len(out) < key.ep.seedsize: 

1435 out += key.prf(chb(count) + pepper) 

1436 count += 1 

1437 return out[: key.ep.seedsize] 

1438 

1439 return Key( 

1440 key1.etype, 

1441 key=bytes( 

1442 _xorbytes( 

1443 bytearray(prfplus(key1, pepper1)), bytearray(prfplus(key2, pepper2)) 

1444 ) 

1445 ), 

1446 )