class Salsa20

Salsa20 stream cipher engine. Initialize the engine with key and iv, and then call Salsa20#encrypt or Salsa20#decrypt (they are actually identical – that's how stream ciphers work).

Example:

encryptor = Salsa20.new(key_str, iv_str)
cipher_text = encryptor.encrypt(plain_text)

Attributes

iv[R]

The encryption IV (Initialization Vector) / nonce

key[R]

The encryption key

Public Class Methods

new(key, iv) click to toggle source

Create a new Salsa20 encryption/decryption engine.

key is the encryption key and must be exactly 128-bits (16 bytes) or 256-bits (32 bytes) long

iv is the encryption IV and must be exactly 64-bits (8 bytes) long

If key or iv lengths are invalid then a Salsa20::InvalidKeyError exception is raised.

# File lib/salsa20.rb, line 41
def initialize(key, iv)
  # do all the possible checks here to make sure the C extension code gets clean variables
  raise TypeError, "key must be a String" unless key.is_a? String
  raise TypeError, "iv must be a String" unless iv.is_a? String

  raise InvalidKeyError, "key length must be 16 or 32 bytes" unless key.size == 16 || key.size == 32
  raise InvalidKeyError, "iv length must be 8 bytes" unless iv.size == 8

  @key = key
  @iv = iv
  @closed = false
  init_context # Implemented in the C extension
end

Public Instance Methods

closed?() click to toggle source

Returns true if the last encryption was of a non 64-bytes boundry chunk. This means this instance cannot be further used (subsequent calls to Salsa20#encrypt or Salsa20#decrypt will raise a Salsa20::EngineClosedError exception); false if the instance can be further used to encrypt/decrypt additional chunks.

# File lib/salsa20.rb, line 60
def closed?
  @closed
end
decrypt(input)
Alias for: encrypt
encrypt(input) click to toggle source

Encrypts/decrypts the string input. If input length is on 64-bytes boundry, you may call encrypt (or decrypt) again; once you call it with a non 64-bytes boundry chunk this must be the final chunk (subsequent calls will raise a Salsa20::EngineClosedError exception).

Returns the encrypted/decrypted string, which has the same size as the input string.

# File lib/salsa20.rb, line 71
def encrypt(input)
  raise TypeError, "input must be a string" unless input.is_a? String
  raise EngineClosedError, "instance is closed" if closed?
  @closed = true if (input.size % 64) != 0
  encrypt_or_decrypt(input) # Implemented in the C extension
end
Also aliased as: decrypt
position() click to toggle source

Returns the current cipher stream position in bytes

# File lib/salsa20.rb, line 92
def position
  get_cipher_position * 64
end
seek(position) click to toggle source

Advance the cipher engine into position (given in bytes). This can be used to start decrypting from the middle of a file, for example.

Note: position must be on a 64-bytes boundry (otherwise a Salsa20::IllegalSeekError exception is raised).

# File lib/salsa20.rb, line 85
def seek(position)
  raise IllegalSeekError, "seek position must be on 64-bytes boundry" unless position % 64 == 0
  position /= 64
  set_cipher_position(low_32bits(position), high_32bits(position)) # Implemented in the C extension
end

Private Instance Methods

encrypt_or_decrypt(p1) click to toggle source
static VALUE rb_salsa20_encrypt_or_decrypt(int argc, VALUE * argv, VALUE self) {
    VALUE input, output;
    ECRYPT_ctx *ctx;

    Data_Get_Struct(self, ECRYPT_ctx, ctx);

    rb_scan_args(argc, argv, "1", &input);
    Check_Type(input, T_STRING);

    output = rb_str_new(0, RSTRING_LEN(input));
    ECRYPT_encrypt_bytes(ctx, (const unsigned char*)RSTRING_PTR(input), (unsigned char*)RSTRING_PTR(output), (unsigned int)RSTRING_LEN(input));

    return output;
}
get_cipher_position() click to toggle source
static VALUE rb_salsa20_get_cipher_position(VALUE self) {
    ECRYPT_ctx *ctx;

    Data_Get_Struct(self, ECRYPT_ctx, ctx);

    return rb_ull2inum(((unsigned LONG_LONG)(ctx->input[9]) << 32) | (unsigned LONG_LONG)(ctx->input[8]));
}
high_32bits(n) click to toggle source
# File lib/salsa20.rb, line 102
def high_32bits(n)
  (n >> 32) & 0xffffffff
end
init_context() click to toggle source
static VALUE rb_salsa20_init_context(VALUE self) {
    VALUE key, iv;
    ECRYPT_ctx *ctx;

    Data_Get_Struct(self, ECRYPT_ctx, ctx);
    key = rb_iv_get(self, "@key");
    iv = rb_iv_get(self, "@iv");

    ECRYPT_keysetup(ctx, (const unsigned char*)RSTRING_PTR(key), (unsigned int)RSTRING_LEN(key) * 8, 64);
    ECRYPT_ivsetup(ctx, (const unsigned char*)RSTRING_PTR(iv));

    return self;
}
low_32bits(n) click to toggle source
# File lib/salsa20.rb, line 98
def low_32bits(n)
  n & 0xffffffff
end
set_cipher_position(p1, p2) click to toggle source
static VALUE rb_salsa20_set_cipher_position(int argc, VALUE * argv, VALUE self) {
    VALUE low_32bits, high_32bits;
    ECRYPT_ctx *ctx;

    Data_Get_Struct(self, ECRYPT_ctx, ctx);

    rb_scan_args(argc, argv, "2", &low_32bits, &high_32bits);
    ctx->input[8] = NUM2INT(low_32bits);
    ctx->input[9] = NUM2INT(high_32bits);

    return Qnil;
}