Class: Rex::Proto::Kerberos::Crypto::DesCbcMd5
- Inherits:
-
BlockCipherBase
- Object
- BlockCipherBase
- Rex::Proto::Kerberos::Crypto::DesCbcMd5
- Includes:
- Asn1Utils
- Defined in:
- lib/rex/proto/kerberos/crypto/des_cbc_md5.rb
Constant Summary collapse
- HASH_LENGTH =
16
- BLOCK_SIZE =
8
- PADDING_SIZE =
8
- MAC_SIZE =
16
Instance Method Summary collapse
-
#decrypt(ciphertext, key, msg_type) ⇒ String
Decrypts the cipher using DES-CBC-MD5 schema.
- #decrypt_asn1(ciphertext, key, msg_type) ⇒ Object
-
#encrypt(plaintext, key, msg_type, confounder: nil) ⇒ String
Encrypts the cipher using DES-CBC-MD5 schema.
-
#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 Asn1Utils
Methods inherited from BlockCipherBase
#add_ones_complement, #calculate_encrypted_length, #checksum, #gss_unwrap, #gss_wrap, #rotate_right
Instance Method Details
#decrypt(ciphertext, key, msg_type) ⇒ String
Decrypts the cipher using DES-CBC-MD5 schema
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 91 def decrypt(ciphertext, key, msg_type) raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Ciphertext too short' unless ciphertext && ciphertext.length > BLOCK_SIZE + HASH_LENGTH raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Ciphertext is not a multiple of block length' unless ciphertext.length % BLOCK_SIZE == 0 cipher = OpenSSL::Cipher.new('des-cbc') if key.length != cipher.key_len raise Rex::Proto::Kerberos::Model::Error::KerberosError, "Decryption key length must be #{cipher.key_len} for des-cbc" end cipher.decrypt cipher.padding = 0 cipher.key = key decrypted = cipher.update(ciphertext) confounder = decrypted[0, BLOCK_SIZE] checksum = decrypted[BLOCK_SIZE, HASH_LENGTH] plaintext = decrypted[BLOCK_SIZE + HASH_LENGTH, decrypted.length] hashed_data = confounder + "\x00" * HASH_LENGTH + plaintext hash_fn = OpenSSL::Digest.new('MD5') if hash_fn.digest(hashed_data) != checksum raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'HMAC integrity error' end plaintext end |
#decrypt_asn1(ciphertext, key, msg_type) ⇒ Object
119 120 121 122 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 119 def decrypt_asn1(ciphertext, key, msg_type) result = decrypt(ciphertext, key, msg_type) padding_removed = truncate_nulls_after_asn1(result) end |
#encrypt(plaintext, key, msg_type, confounder: nil) ⇒ String
Encrypts the cipher using DES-CBC-MD5 schema
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 131 def encrypt(plaintext, key, msg_type, confounder: nil) confounder = Rex::Text::rand_text(BLOCK_SIZE) if confounder == nil padded_data = pad_with_zeroes(plaintext, PADDING_SIZE) hashed_data = confounder + "\x00" * HASH_LENGTH + padded_data hash_fn = OpenSSL::Digest.new('MD5') checksum = hash_fn.digest(hashed_data) raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Invalid checksum size' unless checksum.length == HASH_LENGTH plaintext = confounder + checksum + padded_data cipher = OpenSSL::Cipher.new('des-cbc') if key.length != cipher.key_len raise Rex::Proto::Kerberos::Model::Error::KerberosError, "Encryption key length must be #{cipher.key_len} for des-cbc" end cipher.encrypt cipher.padding = 0 cipher.key = key encrypted = cipher.update(plaintext) + cipher.final encrypted end |
#header_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that precede the actual plaintext
157 158 159 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 157 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
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 23 def string_to_key(password, salt, params: nil) raise Rex::Proto::Kerberos::Model::Error::KerberosError, 'Params not supported for DES' unless params == nil reverse_this_block = false tempstring = [0,0,0,0,0,0,0,0] utf8_encoded = (password + salt).encode('UTF-8').bytes.pack('C*') data = pad_with_zeroes(utf8_encoded, PADDING_SIZE) data_as_blocks = data.unpack('C*') data_as_blocks.each_slice(BLOCK_SIZE) do |block| result = [] block.each do |byte| # Ignore the Most Significant Bit of each byte result.append(byte & 0x7F) end if reverse_this_block reversed = [] result.reverse.each do |byte| d = byte.digits(2) d = d + [0] * (7 - d.length) reversed.append(d.join('').to_i(2)) end result = reversed end reverse_this_block = (not reverse_this_block) tempstring = xor_bytes(tempstring,result) end paritied = addparity(tempstring) tempkey = paritied.pack('C*') if _is_weak_des_key(tempkey) paritied[7] = paritied[7] ^ 0xF0 tempkey = paritied.pack('C*') end cipher = OpenSSL::Cipher.new('des-cbc') cipher.encrypt cipher.padding = 0 cipher.key = tempkey cipher.iv = tempkey encrypted = cipher.update(data) + cipher.final checksumkey = encrypted checksumkey = encrypted[-8,8] paritied = fixparity(checksumkey.unpack('C*')) checksumkey = paritied.pack('C*') if _is_weak_des_key(checksumkey) paritied[7] = paritied[7] ^ 0xF0 checksumkey = paritied.pack('C*') end checksumkey end |
#trailing_byte_count ⇒ Object
The number of bytes in the encrypted plaintext that follow the actual plaintext
164 165 166 |
# File 'lib/rex/proto/kerberos/crypto/des_cbc_md5.rb', line 164 def trailing_byte_count MAC_SIZE end |