Class: EncryptedText::Codec

Inherits:
Object
  • Object
show all
Defined in:
lib/encrypted_text/codec.rb

Constant Summary collapse

KEY_CHAR_SIZES =

An AES key must be 8-bit char strings of these lengths

[16, 24, 32]
DEFAULT_CHARSET =

base 64, URL-safe

Array('A'..'Z') + Array('a'..'z') + Array('0'..'9') + [ '-', '_' ]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Codec

Returns a new instance of Codec.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/encrypted_text/codec.rb', line 16

def initialize(opts)
  config = {
    :charset => DEFAULT_CHARSET,
    :signature => '',
    :key => nil,
    :salt_size => 0,
  }

  config.keys.each do |k|
    # Replace default value with argument
    v = opts.has_key?(k) ? opts[k] : config[k]
    self.send "#{k}=", v
  end
end

Instance Attribute Details

#charsetObject

Returns the value of attribute charset.



11
12
13
# File 'lib/encrypted_text/codec.rb', line 11

def charset
  @charset
end

#keyObject

Returns the value of attribute key.



11
12
13
# File 'lib/encrypted_text/codec.rb', line 11

def key
  @key
end

#salt_sizeObject

Returns the value of attribute salt_size.



11
12
13
# File 'lib/encrypted_text/codec.rb', line 11

def salt_size
  @salt_size
end

#signatureObject

Returns the value of attribute signature.



10
11
12
# File 'lib/encrypted_text/codec.rb', line 10

def signature
  @signature
end

Instance Method Details

#base_decode(val) ⇒ Object



54
55
56
# File 'lib/encrypted_text/codec.rb', line 54

def base_decode(val)
  val.split.map{ |c| @reverse_charset.fetch(c) }.b(@charset.size).to_i
end

#base_encode(val, from_base) ⇒ Object



50
51
52
# File 'lib/encrypted_text/codec.rb', line 50

def base_encode(val, from_base)
  val.b(from_base).to_a.map{ |id| @charset[id] }.join
end

#decode(encoded) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/encrypted_text/codec.rb', line 66

def decode(encoded)
  begin
    hex_string = Radix.convert(encoded, 62, 16)
    hex_string = hex_string[1..-1] if hex_string[0] == '1' # remove "1" prefix
    hex_string = "0" + hex_string if (hex_string.size % 2) != 0 # Make sure we have an even number of hex digits
    byte_string = hex_string.to_byte_string
    decrypted = @engine.decrypt(hex_string.to_byte_string)
  rescue #TODO: don't use generic rescue here
    raise EncryptedText::Err::CannotDecrypt
  end

  # Ensure that the message is signed correctly
  matches = decrypted.match(/^#{Regexp.escape(signature)}(.+)/)
  raise EncryptedText::Err::BadSignature unless matches
  salted_message = matches[1]
  message = salted_message[@salt_size..-1]
end

#encode(message) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/encrypted_text/codec.rb', line 58

def encode(message)
  salt = (0...@salt_size).map { @charset.sample }.join
  signed = @signature + salt + message
  encrypted = @engine.encrypt(signed)
  hex_string = '1' + encrypted.to_hex_string.split(' ').join # Add "1" prefix in case hex_string has leading zeroes
  encoded = Radix.convert(hex_string.upcase, 16, 62) # Radix requires allcaps
end