Home | Trees | Indices | Help |
---|
|
1 # 2 # Copyright (c) 2016, EMC Corporation 3 # All rights reserved. 4 # 5 # Redistribution and use in source and binary forms, with or without 6 # modification, are permitted provided that the following conditions are met: 7 # 8 # 1. Redistributions of source code must retain the above copyright notice, 9 # this list of conditions and the following disclaimer. 10 # 2. Redistributions in binary form must reproduce the above copyright notice, 11 # this list of conditions and the following disclaimer in the documentation 12 # and/or other materials provided with the distribution. 13 # 14 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 # POSSIBILITY OF SUCH DAMAGE. 25 # 26 # Module Name: 27 # 28 # crypto.py 29 # 30 # Abstract: 31 # 32 # SMB3 Encryption 33 # 34 # Authors: Masen Furer (masen.furer@dell.com) 35 # 36 import core 37 import digest 38 import smb2 39 40 import array 41 import random 42 43 from Cryptodome.Cipher import AES 44 4547 if len(value) > length: 48 value = value[:length] 49 elif len(value) < 16: 50 value += array.array('B', byte*(length - len(value))) 51 return value52 53 56 57 62 63 Ciphers.import_items(globals()) 64 65 cipher_map = { 66 SMB2_AES_128_CCM: (AES.MODE_CCM, 11), 67 SMB2_AES_128_GCM: (AES.MODE_GCM, 12) 68 } 69 7072 context_type = smb2.SMB2_ENCRYPTION_CAPABILITIES 73 7789 90 96 97 103 10479 if self.ciphers_count is None: 80 self.ciphers_count = len(self.ciphers) 81 cur.encode_uint16le(self.ciphers_count) 82 for c in self.ciphers: 83 cur.encode_uint16le(c)8486 self.ciphers_count = cur.decode_uint16le() 87 for ix in xrange(self.ciphers_count): 88 self.ciphers.append(Ciphers(cur.decode_uint16le()))106 """ 107 TransformHeader is designed to be a transparent slip attached to a Netbios 108 frame object (specified as parent). During serialization, if a Netbios frame 109 contains an attribute "transform", then that object's encode method will be 110 called instead of each child frames' encode method. This frame is responsible 111 for both encrypting and decrypting Smb2 frames according to an attached 112 encryption context. 113 114 If the encryption_context is not explicitly specified, then it will be looked 115 up based on session_id from the parent Netbios frame's connection reference 116 """251 252118 core.Frame.__init__(self, parent) 119 self.protocol_id = array.array('B', "\xfdSMB") 120 self.signature = None 121 # the value of nonce is always used in the encryption routine 122 self.nonce = array.array('B', 123 map(random.randint, [0]*16, [255]*16)) 124 # if wire_nonce is set, it will be sent on the wire instead of nonce 125 self.wire_nonce = None 126 self.original_message_size = None 127 self.reserved = None 128 self.flags = 0x1 129 self.session_id = None 130 self.encryption_context = None 131 self.additional_authenticated_data_buf = array.array('B') 132 if parent is not None: 133 parent.transform = self 134 else: 135 self._smb2_frames = []136138 if self.parent is not None: 139 return self.parent._children() 140 else: 141 return self._smb2_frames142144 if self.parent is not None: 145 self.parent.append(smb2_frame) 146 else: 147 self._smb2_frames.append(smb2_frame)148 152154 # look up the encryption context if not specified 155 if self.encryption_context is None and self.parent is not None: 156 self.encryption_context = self.parent.conn.encryption_context(self.session_id) 157 cur.encode_bytes(self.protocol_id) 158 159 # the signature will be written in _encode_smb2 160 self.signature_offset = cur.offset 161 cur.advanceto(cur + 16) 162 # the crypto header will be written in _encode_smb2 163 self.crypto_header_offset = cur.offset 164 # save a space for the wire nonce 165 self.wire_nonce_hole = cur.hole.encode_bytes('\0'*16) 166 cur.advanceto(cur + 16) 167 168 # the following fields are part of AdditionalAuthenticatedData and are 169 # used as inputs to the AES cipher 170 aad_cur = core.Cursor(self.additional_authenticated_data_buf, 0) 171 # nonce field size is 16 bytes right padded with zeros 172 self.nonce = pad_right(self.nonce, 16) 173 aad_cur.encode_bytes(self.nonce) 174 self.original_message_size_hole = aad_cur.hole.encode_uint32le(0) 175 if self.reserved is None: 176 self.reserved = 0 177 aad_cur.encode_uint16le(self.reserved) # reserved 178 aad_cur.encode_uint16le(self.flags) 179 aad_cur.encode_uint64le(self.session_id)180182 # serialize all chained Smb2 commands into one buffer 183 original_message_buf = array.array('B') 184 original_message_cur = core.Cursor(original_message_buf, 0) 185 for smb_frame in self.parent: 186 smb_frame.encode(original_message_cur) 187 if self.original_message_size is None: 188 self.original_message_size = len(original_message_buf) 189 self.original_message_size_hole(self.original_message_size) 190 (self.ciphertext, 191 crypto_hmac) = self.encryption_context.encrypt( 192 original_message_buf, 193 self.additional_authenticated_data_buf, 194 self.nonce) 195 cur.encode_bytes(self.ciphertext) 196 197 # fill in the signature hole 198 sig_cur = core.Cursor(cur.array, self.signature_offset) 199 if self.signature is None: 200 self.signature = crypto_hmac 201 sig_cur.encode_bytes(self.signature) 202 203 # fill in the header 204 aad_cur = core.Cursor(cur.array, self.crypto_header_offset) 205 aad_cur.encode_bytes(self.additional_authenticated_data_buf) 206 207 # fill in the wire nonce 208 if self.wire_nonce is None: 209 self.wire_nonce = self.nonce 210 self.wire_nonce_hole(pad_right(self.wire_nonce, 16))211 215217 self.protocol_id = cur.decode_bytes(4) 218 self.signature = cur.decode_bytes(16) 219 # the following fields are part of AdditionalAuthenticatedData and are 220 # used as inputs to the AES cipher 221 self.crypto_header_start = cur.offset 222 self.nonce = cur.decode_bytes(16) 223 self.original_message_size = cur.decode_uint32le() 224 self.reserved = cur.decode_uint16le() # reserved 225 self.flags = cur.decode_uint16le() 226 self.session_id = cur.decode_uint64le() 227 self.crypto_header_end = cur.offset 228 if self.encryption_context is None and self.parent is not None: 229 self.encryption_context = self.parent.conn.encryption_context(self.session_id)230232 self.encrypted_data = cur.decode_bytes(self.original_message_size) 233 crypto_header = cur.array[self.crypto_header_start:self.crypto_header_end] 234 self.plaintext = self.encryption_context.decrypt( 235 self.encrypted_data, 236 self.signature, 237 crypto_header, 238 self.nonce) 239 # scan through the plaintext for chained messages 240 pt_cur = core.Cursor(self.plaintext, 0) 241 end = pt_cur + len(self.plaintext) 242 with pt_cur.bounded(pt_cur, end): 243 while (pt_cur < end): 244 start = pt_cur.offset 245 message = smb2.Smb2(self.parent) 246 message.decode(pt_cur) 247 message.buf = pt_cur.array[start:pt_cur.offset]248254 """ Key generation for SMB 0x300 and 0x302 """260 261256 self.encryption = digest.derive_key( 257 session_key, "SMB2AESCCM", "ServerIn \0")[:16].tostring() 258 self.decryption = digest.derive_key( 259 session_key, "SMB2AESCCM", "ServerOut\0")[:16].tostring()263 """ Key generation for SMB 0x311 + """269 270265 self.encryption = digest.derive_key( 266 session_key, "SMBC2SCipherKey", pre_auth_integrity_hash)[:16].tostring() 267 self.decryption = digest.derive_key( 268 session_key, "SMBS2CCipherKey", pre_auth_integrity_hash)[:16].tostring()272 """ 273 Encapsulates all information needed to encrypt and decrypt messages. 274 This context is attached to an SMB Session object 275 """306277 self.keys = keys 278 for c in ciphers: 279 if c in cipher_map: 280 self.aes_mode, self.nonce_length = cipher_map[c] 281 self.cipher = c 282 break 283 else: 284 raise CipherMismatch( 285 "Client did not recognize any ciphers returned by the " 286 "server: {0}".format(ciphers))287289 enc_cipher = AES.new(self.keys.encryption, 290 self.aes_mode, 291 nonce=nonce[:self.nonce_length].tostring()) 292 enc_cipher.update(authenticated_data.tostring()) 293 ciphertext, signature = enc_cipher.encrypt_and_digest(plaintext.tostring()) 294 return array.array('B', ciphertext), array.array('B', signature)295
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Thu Jun 29 08:51:25 2017 | http://epydoc.sourceforge.net |