# -*- coding: binary -*- module Rex module Proto module Kerberos module Model # This class provides a representation of an encrypted message. class EncryptedData < Element # @!attribute name_type # @return [Fixnum] The encryption algorithm attr_accessor :etype # @!attribute kvno # @return [Fixnum] The version number of the key attr_accessor :kvno # @!attribute cipher # @return [String] The enciphered text attr_accessor :cipher # Decodes a Rex::Proto::Kerberos::Model::EncryptedData # # @param input [String, OpenSSL::ASN1::Sequence] the input to decode from # @return [self] # @raise [RuntimeError] if decoding doesn't succeed def decode(input) case input when String decode_string(input) when OpenSSL::ASN1::Sequence decode_asn1(input) else raise ::RuntimeError, 'Failed to decode EncryptedData Name, invalid input' end self end # Encodes a Rex::Proto::Kerberos::Model::EncryptedData into an ASN.1 String # # @return [String] def encode elems = [] etype_asn1 = OpenSSL::ASN1::ASN1Data.new([encode_etype], 0, :CONTEXT_SPECIFIC) elems << etype_asn1 if kvno kvno_asn1 = OpenSSL::ASN1::ASN1Data.new([encode_kvno], 1, :CONTEXT_SPECIFIC) elems << kvno_asn1 end cipher_asn1 = OpenSSL::ASN1::ASN1Data.new([encode_cipher], 2, :CONTEXT_SPECIFIC) elems << cipher_asn1 seq = OpenSSL::ASN1::Sequence.new(elems) seq.to_der end # Decrypts the cipher with etype encryption schema # # @param key [String] the key to decrypt # @param msg_type [Fixnum] the message type # @return [String] the decrypted `cipher` # @raise [RuntimeError] if decryption doesn't succeed # @raise [NotImplementedError] if encryption isn't supported def decrypt(key, msg_type) if cipher.nil? || cipher.empty? return '' end res = '' case etype when RC4_HMAC res = decrypt_rc4_hmac(cipher, key, msg_type) raise ::RuntimeError, 'EncryptedData failed to decrypt' if res.length < 8 res = res[8, res.length - 1] else raise ::NotImplementedError, 'EncryptedData schema is not supported' end res end private # Encodes the etype # # @return [OpenSSL::ASN1::Integer] def encode_etype bn = OpenSSL::BN.new(etype.to_s) int = OpenSSL::ASN1::Integer.new(bn) int end # Encodes the kvno # # @raise [RuntimeError] def encode_kvno bn = OpenSSL::BN.new(kvno.to_s) int = OpenSSL::ASN1::Integer.new(bn) int end # Encodes the cipher # # @return [OpenSSL::ASN1::OctetString] def encode_cipher OpenSSL::ASN1::OctetString.new(cipher) end # Decodes a Rex::Proto::Kerberos::Model::EncryptedData from an String # # @param input [String] the input to decode from def decode_string(input) asn1 = OpenSSL::ASN1.decode(input) decode_asn1(asn1) end # Decodes a Rex::Proto::Kerberos::Model::EncryptedData from an # OpenSSL::ASN1::Sequence # # @param input [OpenSSL::ASN1::Sequence] the input to decode from # @raise [RuntimeError] if decoding doesn't succeed def decode_asn1(input) seq_values = input.value seq_values.each do |val| case val.tag when 0 self.etype = decode_etype(val) when 1 self.kvno = decode_kvno(val) when 2 self.cipher = decode_cipher(val) else raise ::RuntimeError, 'Failed to decode EncryptedData SEQUENCE' end end end # Decodes the etype from an OpenSSL::ASN1::ASN1Data # # @param input [OpenSSL::ASN1::ASN1Data] the input to decode from # @return [Fixnum] def decode_etype(input) input.value[0].value.to_i end # Decodes the kvno from an OpenSSL::ASN1::ASN1Data # # @param input [OpenSSL::ASN1::ASN1Data] the input to decode from # @return [Fixnum] def decode_kvno(input) input.value[0].value.to_i end # Decodes the cipher from an OpenSSL::ASN1::ASN1Data # # @param input [OpenSSL::ASN1::ASN1Data] the input to decode from # @return [Sting] def decode_cipher(input) input.value[0].value end end end end end end