Class: Rex::Proto::Kerberos::Crypto::AesBlockCipherBase
- Inherits:
-
BlockCipherBase
- Object
- BlockCipherBase
- Rex::Proto::Kerberos::Crypto::AesBlockCipherBase
- Includes:
- GssNewEncryptionType, Utils
- Defined in:
- lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb
Overview
Base class for RFC3962 AES encryption classes
Direct Known Subclasses
Constant Summary collapse
- BLOCK_SIZE =
16
- PADDING_SIZE =
1
- MAC_SIZE =
12
- HASH_FUNCTION =
'SHA1'
Constants included from GssNewEncryptionType
GssNewEncryptionType::GSS_ACCEPTOR_SUBKEY, GssNewEncryptionType::GSS_HEADER_LEN, GssNewEncryptionType::GSS_SEALED, GssNewEncryptionType::GSS_SENT_BY_ACCEPTOR, GssNewEncryptionType::TOK_ID_GSS_WRAP
Instance Method Summary collapse
- #decrypt_basic(ciphertext, key) ⇒ Object
- #encrypt_basic(plaintext, key) ⇒ Object
-
#header_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that precede the actual plaintext.
-
#string_to_key(password, salt, params: nil) ⇒ String
Derive an encryption key based on a password and salt for the given cipher type.
-
#trailing_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that follow the actual plaintext.
Methods included from GssNewEncryptionType
#calculate_encrypted_length, #gss_unwrap, #gss_wrap
Methods included from Utils
Methods inherited from BlockCipherBase
#add_ones_complement, #calculate_encrypted_length, #checksum, #decrypt, #encrypt, #gss_unwrap, #gss_wrap, #rotate_right
Instance Method Details
#decrypt_basic(ciphertext, key) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb', line 59 def decrypt_basic(ciphertext, key) raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Ciphertext too short' if ciphertext.length < BLOCK_SIZE cipher = OpenSSL::Cipher.new(self.class::DECRYPT_CIPHER_NAME) if key.length != cipher.key_len raise Rex::Proto::Kerberos::Model::Error::KerberosError, "Decryption key length must be #{cipher.key_len} for #{self.class::ENCRYPT_CIPHER_NAME}" end cipher.decrypt cipher.key = key cipher.padding = 0 if ciphertext.length == BLOCK_SIZE return cipher.update(ciphertext) + cipher.final end # Split the ciphertext into blocks. The last block may be partial. block_chunks = ciphertext.unpack('C*').each_slice(BLOCK_SIZE).to_a last_block_length = block_chunks[-1].length # CBC-decrypt all but the last two blocks. prev_chunk = [0] * BLOCK_SIZE plaintext_arr = [] block_chunks.slice(0..-3).each do |chunk| decrypted = cipher.update(chunk.pack('C*')) + cipher.final decrypted_arr = decrypted.unpack('C*') plaintext_arr += xor_bytes(decrypted_arr, prev_chunk) prev_chunk = chunk end # Decrypt the second-to-last cipher block. The left side of # the decrypted block will be the final block of plaintext # xor'd with the final partial cipher block; the right side # will be the omitted bytes of ciphertext from the final # block. decrypted = cipher.update(block_chunks[-2].pack('C*')) + cipher.final decrypted_arr = decrypted.unpack('C*') last_plaintext_arr = xor_bytes(decrypted_arr[0, last_block_length], block_chunks[-1]) omitted_arr = decrypted_arr[last_block_length, decrypted.length] # Decrypt the final cipher block plus the omitted bytes to get # the second-to-last plaintext block. decrypted = cipher.update((block_chunks[-1] + omitted_arr).pack('C*')) decrypted_arr = decrypted.unpack('C*') plaintext_arr += xor_bytes(decrypted_arr, prev_chunk) (plaintext_arr + last_plaintext_arr).pack('C*') end |
#encrypt_basic(plaintext, key) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb', line 34 def encrypt_basic(plaintext, key) raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Ciphertext too short' if plaintext.length < BLOCK_SIZE cipher = OpenSSL::Cipher.new(self.class::ENCRYPT_CIPHER_NAME) if key.length != cipher.key_len raise Rex::Proto::Kerberos::Model::Error::KerberosError, "Encryption key length must be #{cipher.key_len} for #{self.class::ENCRYPT_CIPHER_NAME}" end cipher.encrypt cipher.key = key cipher.padding = 0 padded = pad_with_zeroes(plaintext, BLOCK_SIZE) ciphertext = cipher.update(padded) + cipher.final if plaintext.length > BLOCK_SIZE # Swap the last two ciphertext blocks and truncate the # final block to match the plaintext length. last_block_length = plaintext.length % BLOCK_SIZE last_block_length = BLOCK_SIZE if last_block_length == 0 ciphertext = ciphertext[0, ciphertext.length - 32] + ciphertext[-BLOCK_SIZE, BLOCK_SIZE] + ciphertext[-32, last_block_length] end ciphertext end |
#header_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that precede the actual plaintext
111 112 113 |
# File 'lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb', line 111 def header_byte_count BLOCK_SIZE end |
#string_to_key(password, salt, params: nil) ⇒ String
Derive an encryption key based on a password and salt for the given cipher type
26 27 28 29 30 31 32 |
# File 'lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb', line 26 def string_to_key(password, salt, params: nil) params = "\x00\x00\x10\x00" if params == nil iterations = params.unpack('N')[0] seed = OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: iterations, length: self.class::SEED_SIZE, hash: HASH_FUNCTION) tkey = random_to_key(seed) derive(tkey, 'kerberos'.encode('utf-8')) end |
#trailing_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that follow the actual plaintext
118 119 120 |
# File 'lib/rex/proto/kerberos/crypto/aes_block_cipher_base.rb', line 118 def trailing_byte_count MAC_SIZE end |