Class defining a standard encryption dictionary.
Computes the key that will be used to encrypt/decrypt the document contents with owner password. Revision 5 and above.
# File lib/origami/encryption.rb, line 1157 def compute_owner_encryption_key(ownerpassword) if self.R >= 5 passwd = password_to_utf8(ownerpassword) oks = self.O[40, 8] if self.R == 5 okey = Digest::SHA256.digest(passwd + oks + self.U) else okey = compute_hardened_hash(passwd, oks, self.U) end iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*") AES.new(okey, nil, false).decrypt(iv + self.OE.value) end end
Computes the key that will be used to encrypt/decrypt the document contents with user password.
# File lib/origami/encryption.rb, line 1114 def compute_user_encryption_key(userpassword, fileid) if self.R < 5 padded = pad_password(userpassword) padded.force_encoding('binary') if RUBY_VERSION > '1.8' padded << self.O padded << [ self.P ].pack("i") padded << fileid encrypt_metadata = self.EncryptMetadata != false padded << [ -1 ].pack("i") if self.R >= 4 and not encrypt_metadata key = Digest::MD5.digest(padded) 50.times { key = Digest::MD5.digest(key[0, self.Length / 8]) } if self.R >= 3 if self.R == 2 key[0, 5] elsif self.R >= 3 key[0, self.Length / 8] end else passwd = password_to_utf8(userpassword) uks = self.U[40, 8] if self.R == 5 ukey = Digest::SHA256.digest(passwd + uks) else ukey = compute_hardened_hash(passwd, uks) end iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*") AES.new(ukey, nil, false).decrypt(iv + self.UE.value) end end
Checks owner password. For version 2,3 and 4, salt is the document ID. For version 5, salt is (Owner Key Salt + U)
# File lib/origami/encryption.rb, line 1248 def is_owner_password?(pass, salt) if self.R < 5 user_password = retrieve_user_password(pass) is_user_password?(user_password, salt) elsif self.R == 5 ovs = self.O[32, 8] Digest::SHA256.digest(password_to_utf8(pass) + ovs + self.U) == self.O[0, 32] elsif self.R == 6 ovs = self.O[32, 8] compute_hardened_hash(password_to_utf8(pass), ovs, self.U[0,48]) == self.O[0, 32] end end
Checks user password. For version 2,3 and 4, salt is the document ID. For version 5 and 6, salt is the User Key Salt.
# File lib/origami/encryption.rb, line 1229 def is_user_password?(pass, salt) if self.R == 2 compute_user_password(pass, salt) == self.U elsif self.R == 3 or self.R == 4 compute_user_password(pass, salt)[0, 16] == self.U[0, 16] elsif self.R == 5 uvs = self.U[32, 8] Digest::SHA256.digest(password_to_utf8(pass) + uvs) == self.U[0, 32] elsif self.R == 6 uvs = self.U[32, 8] compute_hardened_hash(password_to_utf8(pass), uvs) == self.U[0, 32] end end
Retrieve user password from owner password. Cannot be used with revision 5.
# File lib/origami/encryption.rb, line 1266 def retrieve_user_password(ownerpassword) key = compute_owner_key(ownerpassword) if self.R == 2 ARC4.decrypt(key, self.O) elsif self.R == 3 or self.R == 4 user_password = ARC4.decrypt(xor(key, 19), self.O) 19.times { |i| user_password = ARC4.decrypt(xor(key, 18-i), user_password) } user_password end end
Set up document passwords.
# File lib/origami/encryption.rb, line 1177 def set_passwords(ownerpassword, userpassword, salt = nil) if self.R < 5 key = compute_owner_key(ownerpassword) upadded = pad_password(userpassword) owner_key = ARC4.encrypt(key, upadded) 19.times { |i| owner_key = ARC4.encrypt(xor(key,i+1), owner_key) } if self.R >= 3 self.O = owner_key self.U = compute_user_password(userpassword, salt) else upass = password_to_utf8(userpassword) opass = password_to_utf8(ownerpassword) uvs, uks, ovs, oks = ::Array.new(4) { Encryption.rand_bytes(8) } file_key = Encryption.strong_rand_bytes(32) iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*") if self.R == 5 self.U = Digest::SHA256.digest(upass + uvs) + uvs + uks self.O = Digest::SHA256.digest(opass + ovs + self.U) + ovs + oks ukey = Digest::SHA256.digest(upass + uks) okey = Digest::SHA256.digest(opass + oks + self.U) else self.U = compute_hardened_hash(upass, uvs) + uvs + uks self.O = compute_hardened_hash(opass, ovs, self.U) + ovs + oks ukey = compute_hardened_hash(upass, uks) okey = compute_hardened_hash(opass, oks, self.U) end self.UE = AES.new(ukey, iv, false).encrypt(file_key)[iv.size, 32] self.OE = AES.new(okey, iv, false).encrypt(file_key)[iv.size, 32] perms = [ self.P ].pack("V") + # 0-3 [ -1 ].pack("V") + # 4-7 (self.EncryptMetadata == true ? "T" : "F") + # 8 "adb" + # 9-11 [ 0 ].pack("V") # 12-15 self.Perms = AES.new(file_key, iv, false).encrypt(perms)[iv.size, 16] file_key end end
Generated with the Darkfish Rdoc Generator 2.