class Ssbx::Box

This is the encryption logic. This uses File to read and write data, but the actual encryption logic is in here.

Constants

SYMETRIC_CIPHER_NAME

The symetric cipher name used for the symetric parts of this algorithm.

Public Class Methods

new(file) click to toggle source

Create a new box.

# File lib/ssbx/box.rb, line 15
def initialize(file)
    if file.is_a? IO
        @file = File.new
        @file.read(file)
    elsif file.is_a? Ssbx::File
        @file = file
    else
        raise Exception.new("Unsupported input type #{file.class}. Try Ssbx::File or IO.")
    end
end

Public Instance Methods

list() click to toggle source
# File lib/ssbx/box.rb, line 110
def list
    @file.keys.map { |r| r[0] }
end
read(instream, userid, password) click to toggle source

Decrypt the data user the given user ID and password.

# File lib/ssbx/box.rb, line 78
def read(instream, userid, password)
    @file.read(instream)
    userrecord = @file.keys.select { |k| k[0] == userid }

    # Find or get our user record.
    if userrecord.length == 0 
        raise Exception.new("User #{userid} not found in the file.")
    else
        userrecord = userrecord[0]
    end

    privkey = OpenSSL::PKey::RSA.new(userrecord[1], password)

    cipher = OpenSSL::Cipher.new(SYMETRIC_CIPHER_NAME)
    cipher.decrypt

    cipher.key = privkey.private_decrypt(userrecord[3])
    cipher.iv = userrecord[4]

    data = cipher.update(@file.data)
    data += cipher.final

    data
end
remove_user(user) click to toggle source

Remove a user from the memory representation of this file. You must do a valid write of the file to force credential rotation and remove the user from the file on disk.

# File lib/ssbx/box.rb, line 106
def remove_user(user)
    @file.keys.reject! { |k| k[0] == user }
end
write(outstream, userid, password, data) click to toggle source

Write the data given the userid and password. If the user is not in the file, they are added.

# File lib/ssbx/box.rb, line 28
def write(outstream, userid, password, data)
    userrecord = @file.keys.select { |k| k[0] == userid }

    # Find or get our user record.
    if userrecord.length == 0 
        privkey = OpenSSL::PKey::RSA.new(2048)

        userrecord = [ userid ]
        userrecord << privkey.to_pem(OpenSSL::Cipher.new(SYMETRIC_CIPHER_NAME), password)
        userrecord << privkey.public_key.to_pem
        userrecord << '' # Private Key
        userrecord << '' # Initialization Vector.

        @file.keys << userrecord
    else
        userrecord = userrecord[0]

        privkey = OpenSSL::PKey::RSA.new(2048)

        # Rotate user record entries.
        userrecord[1] = privkey.to_pem(OpenSSL::Cipher.new(SYMETRIC_CIPHER_NAME), password)
        userrecord[2] = privkey.public_key.to_pem
        userrecord[3] = '' # Private Key
        userrecord[4] = '' # Initialization Vector.
    end

    # Make semetric cipher.
    cipher = OpenSSL::Cipher.new(SYMETRIC_CIPHER_NAME)
    cipher.encrypt

    key = cipher.random_key
    iv = cipher.random_iv

    # Encrypt data with key.
    ciphertext = cipher.update(data)
    ciphertext += cipher.final
    @file.data = ciphertext

    # Now update all key records with the new key and iv.
    @file.keys.each do |key_rec|
        # k[0 id, 1 priv, 2 pub, 3 key, 4 iv]
        k = OpenSSL::PKey::RSA.new(key_rec[2])
        key_rec[3] = k.public_encrypt(key)
        key_rec[4] = iv
    end

    @file.write(outstream)
end