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
The encryption IV (Initialization Vector) / nonce
The encryption key
Public Class Methods
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
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
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
Returns the current cipher stream position in bytes
# File lib/salsa20.rb, line 92 def position get_cipher_position * 64 end
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
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; }
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])); }
# File lib/salsa20.rb, line 102 def high_32bits(n) (n >> 32) & 0xffffffff end
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; }
# File lib/salsa20.rb, line 98 def low_32bits(n) n & 0xffffffff end
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; }