salsa20 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/CHANGELOG +3 -0
- data/LICENSE +25 -0
- data/README.rdoc +52 -0
- data/Rakefile +21 -0
- data/ext/salsa20_ext/ecrypt-config.h +272 -0
- data/ext/salsa20_ext/ecrypt-machine.h +46 -0
- data/ext/salsa20_ext/ecrypt-portable.h +303 -0
- data/ext/salsa20_ext/ecrypt-sync.h +279 -0
- data/ext/salsa20_ext/extconf.rb +7 -0
- data/ext/salsa20_ext/salsa20.c +221 -0
- data/ext/salsa20_ext/salsa20_ext.c +87 -0
- data/lib/salsa20.rb +105 -0
- data/salsa20.gemspec +28 -0
- data/test/salsa20_test.rb +140 -0
- metadata +94 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include "ecrypt-sync.h"
|
3
|
+
|
4
|
+
/* Older versions of Ruby (< 1.8.6) need these */
|
5
|
+
#ifndef RSTRING_PTR
|
6
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
7
|
+
#endif
|
8
|
+
#ifndef RSTRING_LEN
|
9
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
10
|
+
#endif
|
11
|
+
#ifndef RARRAY_PTR
|
12
|
+
#define RARRAY_PTR(s) (RARRAY(s)->ptr)
|
13
|
+
#endif
|
14
|
+
#ifndef RARRAY_LEN
|
15
|
+
#define RARRAY_LEN(s) (RARRAY(s)->len)
|
16
|
+
#endif
|
17
|
+
|
18
|
+
static VALUE cSalsa20;
|
19
|
+
|
20
|
+
static VALUE rb_salsa20_alloc(VALUE klass) {
|
21
|
+
VALUE obj;
|
22
|
+
ECRYPT_ctx *ctx;
|
23
|
+
|
24
|
+
obj = Data_Make_Struct(klass, ECRYPT_ctx, 0, 0, ctx);
|
25
|
+
return obj;
|
26
|
+
}
|
27
|
+
|
28
|
+
static VALUE rb_salsa20_init_context(VALUE self) {
|
29
|
+
VALUE key, iv;
|
30
|
+
ECRYPT_ctx *ctx;
|
31
|
+
|
32
|
+
Data_Get_Struct(self, ECRYPT_ctx, ctx);
|
33
|
+
key = rb_iv_get(self, "@key");
|
34
|
+
iv = rb_iv_get(self, "@iv");
|
35
|
+
|
36
|
+
ECRYPT_keysetup(ctx, (const unsigned char*)RSTRING_PTR(key), (unsigned int)RSTRING_LEN(key) * 8, 64);
|
37
|
+
ECRYPT_ivsetup(ctx, (const unsigned char*)RSTRING_PTR(iv));
|
38
|
+
|
39
|
+
return self;
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE rb_salsa20_encrypt_or_decrypt(int argc, VALUE * argv, VALUE self) {
|
43
|
+
VALUE input, output;
|
44
|
+
ECRYPT_ctx *ctx;
|
45
|
+
|
46
|
+
Data_Get_Struct(self, ECRYPT_ctx, ctx);
|
47
|
+
|
48
|
+
rb_scan_args(argc, argv, "1", &input);
|
49
|
+
Check_Type(input, T_STRING);
|
50
|
+
|
51
|
+
output = rb_str_new(0, RSTRING_LEN(input));
|
52
|
+
ECRYPT_encrypt_bytes(ctx, (const unsigned char*)RSTRING_PTR(input), (unsigned char*)RSTRING_PTR(output), (unsigned int)RSTRING_LEN(input));
|
53
|
+
|
54
|
+
return output;
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE rb_salsa20_set_cipher_position(int argc, VALUE * argv, VALUE self) {
|
58
|
+
VALUE low_32bits, high_32bits;
|
59
|
+
ECRYPT_ctx *ctx;
|
60
|
+
|
61
|
+
Data_Get_Struct(self, ECRYPT_ctx, ctx);
|
62
|
+
|
63
|
+
rb_scan_args(argc, argv, "2", &low_32bits, &high_32bits);
|
64
|
+
ctx->input[8] = NUM2INT(low_32bits);
|
65
|
+
ctx->input[9] = NUM2INT(high_32bits);
|
66
|
+
|
67
|
+
return Qnil;
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE rb_salsa20_get_cipher_position(VALUE self) {
|
71
|
+
ECRYPT_ctx *ctx;
|
72
|
+
|
73
|
+
Data_Get_Struct(self, ECRYPT_ctx, ctx);
|
74
|
+
|
75
|
+
return rb_ull2inum(((unsigned LONG_LONG)(ctx->input[9]) << 32) | (unsigned LONG_LONG)(ctx->input[8]));
|
76
|
+
}
|
77
|
+
|
78
|
+
void Init_salsa20_ext() {
|
79
|
+
cSalsa20 = rb_define_class("Salsa20", rb_cObject);
|
80
|
+
|
81
|
+
rb_define_alloc_func(cSalsa20, rb_salsa20_alloc);
|
82
|
+
|
83
|
+
rb_define_private_method(cSalsa20, "init_context", rb_salsa20_init_context, 0);
|
84
|
+
rb_define_private_method(cSalsa20, "encrypt_or_decrypt", rb_salsa20_encrypt_or_decrypt, -1);
|
85
|
+
rb_define_private_method(cSalsa20, "set_cipher_position", rb_salsa20_set_cipher_position, -1);
|
86
|
+
rb_define_private_method(cSalsa20, "get_cipher_position", rb_salsa20_get_cipher_position, 0);
|
87
|
+
}
|
data/lib/salsa20.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'salsa20_ext'
|
2
|
+
|
3
|
+
# Salsa20 stream cipher engine. Initialize the engine with +key+ and +iv+, and
|
4
|
+
# then call Salsa20#encrypt or Salsa20#decrypt (they are actually identical --
|
5
|
+
# that's how stream ciphers work).
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# encryptor = Salsa20.new(key_str, iv_str)
|
10
|
+
# cipher_text = encryptor.encrypt(plain_text)
|
11
|
+
#
|
12
|
+
class Salsa20
|
13
|
+
|
14
|
+
# Salsa20 engine was initialized withe a key of the wrong length (see Salsa20#new).
|
15
|
+
class InvalidKeyError < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
# Salsa20#encrypt was called after a non 64-bytes boundry block
|
19
|
+
class EngineClosedError < StandardError
|
20
|
+
end
|
21
|
+
|
22
|
+
# Salsa20#seek was called with a non 64-bytes boundry position
|
23
|
+
class IllegalSeekError < StandardError
|
24
|
+
end
|
25
|
+
|
26
|
+
# The encryption key
|
27
|
+
attr_reader :key
|
28
|
+
|
29
|
+
# The encryption IV (Initialization Vector) / nonce
|
30
|
+
attr_reader :iv
|
31
|
+
|
32
|
+
# Create a new Salsa20 encryption/decryption engine.
|
33
|
+
#
|
34
|
+
# +key+ is the encryption key and must be exactly 128-bits (16 bytes) or
|
35
|
+
# 256-bits (32 bytes) long
|
36
|
+
#
|
37
|
+
# +iv+ is the encryption IV and must be exactly 64-bits (8 bytes) long
|
38
|
+
#
|
39
|
+
# If +key+ or +iv+ lengths are invalid then a Salsa20::InvalidKeyError
|
40
|
+
# exception is raised.
|
41
|
+
def initialize(key, iv)
|
42
|
+
# do all the possible checks here to make sure the C extension code gets clean variables
|
43
|
+
raise TypeError, "key must be a String" unless key.is_a? String
|
44
|
+
raise TypeError, "iv must be a String" unless iv.is_a? String
|
45
|
+
|
46
|
+
raise InvalidKeyError, "key length must be 16 or 32 bytes" unless key.size == 16 || key.size == 32
|
47
|
+
raise InvalidKeyError, "iv length must be 8 bytes" unless iv.size == 8
|
48
|
+
|
49
|
+
@key = key
|
50
|
+
@iv = iv
|
51
|
+
@closed = false
|
52
|
+
init_context # Implemented in the C extension
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns _true_ if the last encryption was of a non 64-bytes boundry chunk.
|
56
|
+
# This means this instance cannot be further used (subsequent calls to
|
57
|
+
# Salsa20#encrypt or Salsa20#decrypt will raise a Salsa20::EngineClosedError
|
58
|
+
# exception); _false_ if the instance can be further used to encrypt/decrypt
|
59
|
+
# additional chunks.
|
60
|
+
def closed?
|
61
|
+
@closed
|
62
|
+
end
|
63
|
+
|
64
|
+
# Encrypts/decrypts the string +input+. If +input+ length is on 64-bytes
|
65
|
+
# boundry, you may call encrypt (or decrypt) again; once you call it with a
|
66
|
+
# non 64-bytes boundry chunk this must be the final chunk (subsequent calls will
|
67
|
+
# raise a Salsa20::EngineClosedError exception).
|
68
|
+
#
|
69
|
+
# Returns the encrypted/decrypted string, which has the same size as the
|
70
|
+
# input string.
|
71
|
+
def encrypt(input)
|
72
|
+
raise TypeError, "input must be a string" unless input.is_a? String
|
73
|
+
raise EngineClosedError, "instance is closed" if closed?
|
74
|
+
@closed = true if (input.size % 64) != 0
|
75
|
+
encrypt_or_decrypt(input) # Implemented in the C extension
|
76
|
+
end
|
77
|
+
|
78
|
+
alias :decrypt :encrypt
|
79
|
+
|
80
|
+
# Advance the cipher engine into +position+ (given in bytes). This can be
|
81
|
+
# used to start decrypting from the middle of a file, for example.
|
82
|
+
#
|
83
|
+
# Note: +position+ must be on a 64-bytes boundry (otherwise a
|
84
|
+
# Salsa20::IllegalSeekError exception is raised).
|
85
|
+
def seek(position)
|
86
|
+
raise IllegalSeekError, "seek position must be on 64-bytes boundry" unless position % 64 == 0
|
87
|
+
position /= 64
|
88
|
+
set_cipher_position(low_32bits(position), high_32bits(position)) # Implemented in the C extension
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the current cipher stream position in bytes
|
92
|
+
def position
|
93
|
+
get_cipher_position * 64
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def low_32bits(n)
|
99
|
+
n & 0xffffffff
|
100
|
+
end
|
101
|
+
|
102
|
+
def high_32bits(n)
|
103
|
+
(n >> 32) & 0xffffffff
|
104
|
+
end
|
105
|
+
end
|
data/salsa20.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'salsa20'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
|
5
|
+
s.summary = "Salsa20 stream cipher algorithm."
|
6
|
+
s.description = <<-EOF
|
7
|
+
Salsa20 is a stream cipher algorithm designed by Daniel Bernstein. salsa20-ruby provides
|
8
|
+
a simple Ruby wrapper.
|
9
|
+
EOF
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.require_path = 'lib'
|
13
|
+
|
14
|
+
s.test_files = `git ls-files test`.split("\n")
|
15
|
+
|
16
|
+
s.add_development_dependency 'rdoc'
|
17
|
+
s.add_development_dependency 'rake-compiler'
|
18
|
+
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.rdoc_options += ['--title', 'salsa20', '--main', 'README.rdoc']
|
21
|
+
s.extra_rdoc_files += ['README.rdoc', 'LICENSE', 'CHANGELOG', 'lib/salsa20.rb']
|
22
|
+
|
23
|
+
s.extensions = 'ext/salsa20_ext/extconf.rb'
|
24
|
+
|
25
|
+
s.authors = ["Dov Murik"]
|
26
|
+
s.email = "dov.murik@gmail.com"
|
27
|
+
s.homepage = "https://github.com/dubek/salsa20-ruby"
|
28
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "salsa20"))
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class Salsa20Test < Test::Unit::TestCase
|
5
|
+
def test_salsa20_keystream
|
6
|
+
expected = "@\x8D\x94\xF48f9Z)\e\xBD\xB8?\xCC\xEC\xD6g\xB3;\xC7ev\v\xCA]\xEE\x19I;\xA2<\\^\xCEFQn\x94B{+\x06\xE2\x85\x9F\xEC\xBBp@\xA4\x8F\xD8~\xD3\x12\x197\f\xD7'\x8C\xC8\xEF\xFC"
|
7
|
+
assert_equal expected, Salsa20.new("K"*32, "I"*8).encrypt("\x00"*64)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_bad_number_of_arguments_for_new_should_raise_exception
|
11
|
+
assert_raise(ArgumentError) { Salsa20.new }
|
12
|
+
assert_raise(ArgumentError) { Salsa20.new("K"*32) }
|
13
|
+
assert_raise(ArgumentError) { Salsa20.new("K"*32, "I"*8, "third") }
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_non_string_arguments_for_new_should_raise_exception
|
17
|
+
assert_raise(TypeError) { Salsa20.new([1,2,3], "I"*8) }
|
18
|
+
assert_raise(TypeError) { Salsa20.new("K"*32, { "a" => "b"}) }
|
19
|
+
assert_raise(TypeError) { Salsa20.new([1,2,3], { "a" => "b"}) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_invalid_key_length_should_raise_exception
|
23
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*15, "I"*8) }
|
24
|
+
assert_nothing_raised { Salsa20.new("K"*16, "I"*8) }
|
25
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*17, "I"*8) }
|
26
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*31, "I"*8) }
|
27
|
+
assert_nothing_raised { Salsa20.new("K"*32, "I"*8) }
|
28
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*33, "I"*8) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_invalid_iv_length_should_raise_exception
|
32
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*32, "I"*7) }
|
33
|
+
assert_nothing_raised { Salsa20.new("K"*32, "I"*8) }
|
34
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*32, "I"*9) }
|
35
|
+
assert_raise(Salsa20::InvalidKeyError) { Salsa20.new("K"*32, "I"*16) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_accessors
|
39
|
+
the_key = "K"*32
|
40
|
+
the_iv = "I"*8
|
41
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
42
|
+
assert_equal the_key, encryptor.key
|
43
|
+
assert_equal the_iv, encryptor.iv
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_encrypt_and_decrypt_with_256_bit_key
|
47
|
+
the_key = "A"*32
|
48
|
+
the_iv = "B"*8
|
49
|
+
plain_text = "the quick brown fox jumped over the lazy dog"
|
50
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
51
|
+
cipher_text = encryptor.encrypt(plain_text)
|
52
|
+
assert_equal plain_text.size, cipher_text.size
|
53
|
+
decryptor = Salsa20.new(the_key, the_iv)
|
54
|
+
assert_equal plain_text, decryptor.decrypt(cipher_text)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_encrypted_encoding_should_be_binary
|
58
|
+
return unless "TEST".respond_to?(:encoding)
|
59
|
+
save_encoding = Encoding.default_external
|
60
|
+
Encoding.default_external = "UTF-8"
|
61
|
+
the_key = "A"*32
|
62
|
+
the_iv = "B"*8
|
63
|
+
plain_text = "the quick brown fox jumped over the lazy dog"
|
64
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
65
|
+
cipher_text = encryptor.encrypt(plain_text)
|
66
|
+
assert_equal Encoding.find("ASCII-8BIT"), cipher_text.encoding
|
67
|
+
assert_equal Encoding.find("BINARY"), cipher_text.encoding
|
68
|
+
Encoding.default_external = save_encoding
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_encrypt_and_decrypt_with_128_bit_key
|
72
|
+
the_key = "C"*16
|
73
|
+
the_iv = "D"*8
|
74
|
+
plain_text = "the quick brown fox jumped over the lazy dog"
|
75
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
76
|
+
cipher_text = encryptor.encrypt(plain_text)
|
77
|
+
assert_equal plain_text.size, cipher_text.size
|
78
|
+
decryptor = Salsa20.new(the_key, the_iv)
|
79
|
+
assert_equal plain_text, decryptor.decrypt(cipher_text)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_multiple_encrypt_and_one_decrypt
|
83
|
+
the_key = "E"*32
|
84
|
+
the_iv = "F"*8
|
85
|
+
plain_text = "the quick brown fox jumped over the lazy dog" * 5
|
86
|
+
parts = [ plain_text[0,64], plain_text[64,64], plain_text[128,64], plain_text[192,64] ]
|
87
|
+
assert_equal plain_text, parts.join
|
88
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
89
|
+
cipher_text = parts.map { |part| encryptor.encrypt(part) }.join
|
90
|
+
assert_equal true, encryptor.closed?
|
91
|
+
assert_equal plain_text.size, cipher_text.size
|
92
|
+
decryptor = Salsa20.new(the_key, the_iv)
|
93
|
+
assert_equal plain_text, decryptor.decrypt(cipher_text)
|
94
|
+
assert_equal true, decryptor.closed?
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_encrypt_after_non_64_bytes_should_raise_exception
|
98
|
+
the_key = "G"*32
|
99
|
+
the_iv = "H"*8
|
100
|
+
part1 = "a"*63
|
101
|
+
part2 = "b"*64
|
102
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
103
|
+
assert_equal false, encryptor.closed?
|
104
|
+
encryptor.encrypt(part1)
|
105
|
+
assert_equal true, encryptor.closed?
|
106
|
+
assert_raise(Salsa20::EngineClosedError) { encryptor.encrypt(part2) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_seek
|
110
|
+
the_key = "I"*32
|
111
|
+
the_iv = "J"*8
|
112
|
+
plain_text = "the quick brown fox jumped over the lazy dog" * 5
|
113
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
114
|
+
cipher_text = encryptor.encrypt(plain_text)
|
115
|
+
decryptor = Salsa20.new(the_key, the_iv)
|
116
|
+
assert_equal 0, decryptor.position
|
117
|
+
cipher_text.slice!(0,128)
|
118
|
+
decryptor.seek(128)
|
119
|
+
assert_equal 128, decryptor.position
|
120
|
+
assert_equal plain_text[128..-1], decryptor.decrypt(cipher_text)
|
121
|
+
assert_equal 256, decryptor.position
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_seek_to_non_64_bytes_boundry_should_raise_exception
|
125
|
+
the_key = "K"*32
|
126
|
+
the_iv = "L"*8
|
127
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
128
|
+
assert_raise(Salsa20::IllegalSeekError) { encryptor.seek(65) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_seek_and_position_to_large_positions
|
132
|
+
the_key = "M"*32
|
133
|
+
the_iv = "N"*8
|
134
|
+
large_position = 1 << 50
|
135
|
+
encryptor = Salsa20.new(the_key, the_iv)
|
136
|
+
assert_equal 0, encryptor.position
|
137
|
+
encryptor.seek(large_position)
|
138
|
+
assert_equal large_position, encryptor.position
|
139
|
+
end
|
140
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: salsa20
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dov Murik
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-20 00:00:00.000000000 +03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rdoc
|
17
|
+
requirement: &2156666300 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2156666300
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake-compiler
|
28
|
+
requirement: &2156665860 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2156665860
|
37
|
+
description: ! " Salsa20 is a stream cipher algorithm designed by Daniel Bernstein.
|
38
|
+
salsa20-ruby provides\n a simple Ruby wrapper.\n"
|
39
|
+
email: dov.murik@gmail.com
|
40
|
+
executables: []
|
41
|
+
extensions:
|
42
|
+
- ext/salsa20_ext/extconf.rb
|
43
|
+
extra_rdoc_files:
|
44
|
+
- README.rdoc
|
45
|
+
- LICENSE
|
46
|
+
- CHANGELOG
|
47
|
+
- lib/salsa20.rb
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- CHANGELOG
|
51
|
+
- LICENSE
|
52
|
+
- README.rdoc
|
53
|
+
- Rakefile
|
54
|
+
- ext/salsa20_ext/ecrypt-config.h
|
55
|
+
- ext/salsa20_ext/ecrypt-machine.h
|
56
|
+
- ext/salsa20_ext/ecrypt-portable.h
|
57
|
+
- ext/salsa20_ext/ecrypt-sync.h
|
58
|
+
- ext/salsa20_ext/extconf.rb
|
59
|
+
- ext/salsa20_ext/salsa20.c
|
60
|
+
- ext/salsa20_ext/salsa20_ext.c
|
61
|
+
- lib/salsa20.rb
|
62
|
+
- salsa20.gemspec
|
63
|
+
- test/salsa20_test.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: https://github.com/dubek/salsa20-ruby
|
66
|
+
licenses: []
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --title
|
70
|
+
- salsa20
|
71
|
+
- --main
|
72
|
+
- README.rdoc
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.6.2
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: Salsa20 stream cipher algorithm.
|
93
|
+
test_files:
|
94
|
+
- test/salsa20_test.rb
|