Class: Salmon::SalmonSlap

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

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Instance Attribute Details

- (Object) aes_key

Returns the value of attribute aes_key



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def aes_key
  @aes_key
end

- (Object) author

Returns the value of attribute author



44
45
46
47
48
49
50
# File 'lib/salmon/salmon.rb', line 44

def author
  if @author.nil?
    @author ||= Person. @author_email
    raise "did you remember to async webfinger?" if @author.nil?
  end
  @author
end

- (Object) author_email

Returns the value of attribute author_email



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def author_email
  @author_email
end

- (Object) data_type

Returns the value of attribute data_type



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def data_type
  @data_type
end

- (Object) iv

Returns the value of attribute iv



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def iv
  @iv
end

- (Object) magic_sig

Returns the value of attribute magic_sig



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def magic_sig
  @magic_sig
end

- (Object) parsed_data

Returns the value of attribute parsed_data



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def parsed_data
  @parsed_data
end

- (Object) sig

Returns the value of attribute sig



44
45
46
# File 'lib/salmon/salmon.rb', line 44

def sig
  @sig
end

Class Method Details

+ (Object) b64_to_n(str)

Decode a string containing URL safe Base64 into an integer Example:

  MagicSig.b64_to_n('AQAB')
  # -> 645537


153
154
155
156
# File 'lib/salmon/salmon.rb', line 153

def self.b64_to_n(str)
  packed = decode64url(str)
  packed.unpack('B*')[0].to_i(2)
end

+ (Object) build_key(n, e)

Take two integers e, n and create a new OpenSSL::PKey::RSA key with them Example:

  n = 9487834027867356975347184933768917275269369900665861930617802608089634337052392076689226301419587057117740995382286148368168197915234368486155306558161867
  e = 65537
  key = MagicSig.build_key(n,e)
  key.public_encrypt(...) # for sending to strangers
  key.public_decrypt(...) # very rarely used
  key.verify(...) # for verifying signatures


180
181
182
183
184
185
# File 'lib/salmon/salmon.rb', line 180

def self.build_key(n,e)
  key = OpenSSL::PKey::RSA.new
  key.n = n
  key.e = e
  key
end

+ (Object) create(user, activity)



47
48
49
50
51
52
53
54
55
# File 'lib/salmon/salmon.rb', line 47

def self.create(user, activity)
  salmon = self.new
  salmon.author = user.person
  aes_key_hash = user.person.gen_aes_key
  salmon.aes_key = aes_key_hash['key']
  salmon.iv      = aes_key_hash['iv']
  salmon.magic_sig = MagicSigEnvelope.create(user , user.person.aes_encrypt(activity, aes_key_hash))
  salmon
end

+ (Object) decode64url(str)

Decode URL-safe-Base64. This implements



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/salmon/salmon.rb', line 123

def self.decode64url(str)
  # remove whitespace
  sans_whitespace = str.gsub(/\s/, '')
  # pad to a multiple of 4
  string = sans_whitespace + '=' * ((4 - sans_whitespace.size) % 4)
  # convert to standard Base64
  # string = padded.tr('-','+').tr('_','/')

  # Base64.decode64(string)
  Base64.urlsafe_decode64 string
end

+ (Object) parse(xml, user)

Raises:

  • (ArgumentError)


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
83
84
85
86
# File 'lib/salmon/salmon.rb', line 57

def self.parse(xml, user)
  slap = self.new
  doc = Nokogiri::XML(xml)

  sig_doc = doc.search('entry')

  ### Header ##
  decrypted_header = user.decrypt(doc.search('encrypted_header').text)
  header_doc       = Nokogiri::XML(decrypted_header)
  slap.author_email= header_doc.search('uri').text.split("acct:").last
  slap.aes_key     = header_doc.search('aes_key').text
  slap.iv          = header_doc.search('iv').text

  slap.magic_sig = MagicSigEnvelope.parse sig_doc

  if  'base64url' == slap.magic_sig.encoding

    key_hash = {'key' => slap.aes_key, 'iv' => slap.iv}
    slap.parsed_data = user.aes_decrypt(decode64url(slap.magic_sig.data), key_hash)
    slap.sig = slap.magic_sig.sig
  else
    raise ArgumentError, "Magic Signature data must be encoded with base64url, was #{slap.magic_sig.encoding}"
  end

  slap.data_type = slap.magic_sig.data_type

  raise ArgumentError, "Magic Signature data must be signed with RSA-SHA256, was #{slap.magic_sig.alg}" unless 'RSA-SHA256' == slap.magic_sig.alg

  slap
end

+ (Object) parse_key(str)

Parse a string containing a magic-public-key into an OpenSSL::PKey::RSA key. Example:

  key = MagicSig.parse_key('RSA.mVgY8RN6URBTstndvmUUPb4UZTdwvwmddSKE5z_jvKUEK6yk1u3rrC9yN8k6FilGj9K0eeUPe2hf4Pj-5CmHww.AQAB')
  key.n
  # -> 8031283789075196565022891546563591368344944062154100509645398892293433370859891943306439907454883747534493461257620351548796452092307094036643522661681091
  key.e
  # -> 65537


166
167
168
169
# File 'lib/salmon/salmon.rb', line 166

def self.parse_key(str)
  n,e = str.match(/^RSA.([^.]*).([^.]*)$/)[1..2]
  build_key(b64_to_n(n),b64_to_n(e))
end

Instance Method Details

- (Object) decrypted_header



100
101
102
# File 'lib/salmon/salmon.rb', line 100

def decrypted_header
  header ="    <decrypted_header>\n    <iv>\#{iv}</iv>\n    <aes_key>\#{aes_key}</aes_key>\n    <author>\n      <name>\#{@author.name}</name>\n      <uri>acct:\#{@author.diaspora_handle}</uri>\n    </author>\n    </decrypted_header>\n"
end

- (Boolean) verified_for_key?(public_key)

Check whether this envelope’s signature can be verified with the provided OpenSSL::PKey::RSA public_key. Example:

  env.verified_for_key? OpenSSL::PKey::RSA.new(File.open('public_key.pem'))
  # -> true

Returns:

  • (Boolean)


141
142
143
144
145
146
# File 'lib/salmon/salmon.rb', line 141

def verified_for_key?(public_key)
  signature = Base64.urlsafe_decode64(self.magic_sig.sig)
  signed_data = self.magic_sig.signable_string# Base64.urlsafe_decode64(self.magic_sig.signable_string)

  public_key.verify(OpenSSL::Digest::SHA256.new, signature, signed_data )
end

- (Object) xml_for(person)



88
89
90
91
# File 'lib/salmon/salmon.rb', line 88

def xml_for person
  xml ="    <?xml version='1.0' encoding='UTF-8'?>\n    <entry xmlns='http://www.w3.org/2005/Atom'>\n    <encrypted_header>\#{person.encrypt(decrypted_header)}</encrypted_header>\n      \#{@magic_sig.to_xml}\n      </entry>\n"

end