rmega 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +82 -0
- data/Rakefile +2 -0
- data/lib/rmega.rb +50 -0
- data/lib/rmega/crypto/aes.rb +33 -0
- data/lib/rmega/crypto/aes_ctr.rb +89 -0
- data/lib/rmega/crypto/crypto.rb +94 -0
- data/lib/rmega/crypto/rsa.rb +19 -0
- data/lib/rmega/crypto/rsa_mega.js +455 -0
- data/lib/rmega/node.rb +128 -0
- data/lib/rmega/session.rb +78 -0
- data/lib/rmega/storage.rb +146 -0
- data/lib/rmega/utils.rb +197 -0
- data/lib/rmega/version.rb +3 -0
- data/rmega.gemspec +23 -0
- data/spec/rmega/lib/crypto/aes_spec.rb +12 -0
- data/spec/rmega/lib/crypto/crypto_spec.rb +27 -0
- data/spec/rmega/lib/utils_spec.rb +66 -0
- data/spec/spec_helper.rb +12 -0
- metadata +150 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Daniele Molteni
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Rmega
|
2
|
+
|
3
|
+
Ruby library for the Mega.co.nz API.
|
4
|
+
Tested using ruby 1.9.3+ (OpenSSL 0.9.8r+)
|
5
|
+
|
6
|
+
<div style="background-color: #000000; border-radius: 8px">
|
7
|
+
<img src="https://eu.static.mega.co.nz/images/mega/logo.png" />
|
8
|
+
</div>
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
storage = Rmega.login 'your_email', 'your_password'
|
16
|
+
|
17
|
+
# Fetch all the nodes (files, folders, ecc.)
|
18
|
+
nodes = storage.nodes
|
19
|
+
|
20
|
+
# Find all nodes which name match a regexp
|
21
|
+
nodes = storage.nodes_by_name /my.document/i
|
22
|
+
|
23
|
+
# Download a file
|
24
|
+
my_node.download '~/Download' # The name of the node is used
|
25
|
+
my_node.download '~/Download/mydocument_42.zip' # Specify a new name
|
26
|
+
|
27
|
+
# Download a file using a given url
|
28
|
+
storage.download 'https://mega.co.nz/#!cER0GYbD!ZCHruEzLghAcEZuD44Dp0k--6m5duA08Xl4a_bUZYMI', '~/Download'
|
29
|
+
|
30
|
+
# Upload a file (to the root node)
|
31
|
+
storage.upload '~/Downloads/my_file.zip'
|
32
|
+
|
33
|
+
# Upload a file to a specific folder
|
34
|
+
storage.upload '~/Downloads/my_file.zip', folder_node
|
35
|
+
|
36
|
+
# Trash a node
|
37
|
+
my_node.trash
|
38
|
+
|
39
|
+
# Gets the public url (the sharable one) of a file
|
40
|
+
my_node.public_url
|
41
|
+
|
42
|
+
# See the attributes of a node
|
43
|
+
my_node.attributes
|
44
|
+
|
45
|
+
# Find all nodes of certain type
|
46
|
+
# types are: file, dir, root, inbox, trash
|
47
|
+
files = storage.nodes_by_type :file
|
48
|
+
folders = storage.nodes_by_type :dir
|
49
|
+
|
50
|
+
```
|
51
|
+
|
52
|
+
|
53
|
+
## Installation
|
54
|
+
|
55
|
+
Add this line to your application's Gemfile:
|
56
|
+
|
57
|
+
gem 'rmega'
|
58
|
+
|
59
|
+
And then execute:
|
60
|
+
|
61
|
+
$ bundle
|
62
|
+
|
63
|
+
Or install it yourself as:
|
64
|
+
|
65
|
+
$ gem install rmega
|
66
|
+
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
1. Fork it
|
71
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
72
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
73
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
74
|
+
5. Create new Pull Request
|
75
|
+
|
76
|
+
|
77
|
+
## Copyright
|
78
|
+
|
79
|
+
This work is the result of a reverse engineering of the Mega's Javascript code.
|
80
|
+
|
81
|
+
Copyright (c) 2013 Daniele Molteni
|
82
|
+
MIT License
|
data/Rakefile
ADDED
data/lib/rmega.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Gem with ruby 1.9+
|
2
|
+
require "openssl"
|
3
|
+
require "json"
|
4
|
+
require "logger"
|
5
|
+
require "ostruct"
|
6
|
+
|
7
|
+
# Gems in the bundle
|
8
|
+
require "httpclient"
|
9
|
+
require "execjs"
|
10
|
+
require "ruby-progressbar"
|
11
|
+
|
12
|
+
# Require all the other files
|
13
|
+
require "rmega/version"
|
14
|
+
require "rmega/utils"
|
15
|
+
require "rmega/crypto/rsa"
|
16
|
+
require "rmega/crypto/aes"
|
17
|
+
require "rmega/crypto/aes_ctr"
|
18
|
+
require "rmega/crypto/crypto"
|
19
|
+
require "rmega/storage"
|
20
|
+
require "rmega/node"
|
21
|
+
require "rmega/session"
|
22
|
+
|
23
|
+
module Rmega
|
24
|
+
def self.logger
|
25
|
+
@logger ||= begin
|
26
|
+
logger = Logger.new $stdout
|
27
|
+
logger.formatter = Proc.new { | severity, time, progname, msg| "#{msg}\n" }
|
28
|
+
logger.level = Logger::INFO
|
29
|
+
logger
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.login email, password
|
34
|
+
session = Session.new email, password
|
35
|
+
session.storage
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.default_options
|
39
|
+
{
|
40
|
+
show_progress: true,
|
41
|
+
upload_timeout: 120,
|
42
|
+
api_request_timeout: 20,
|
43
|
+
api_url: 'https://eu.api.mega.co.nz/cs'
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.options
|
48
|
+
@options ||= OpenStruct.new default_options
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rmega
|
2
|
+
module Crypto
|
3
|
+
module Aes
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def packing
|
7
|
+
'l>*'
|
8
|
+
end
|
9
|
+
|
10
|
+
def cipher
|
11
|
+
@cipher ||= OpenSSL::Cipher::AES.new 128, :CBC
|
12
|
+
end
|
13
|
+
|
14
|
+
def encrypt key, data
|
15
|
+
cipher.reset
|
16
|
+
cipher.padding = 0
|
17
|
+
cipher.encrypt
|
18
|
+
cipher.key = key.pack(packing)
|
19
|
+
result = cipher.update data.pack(packing)
|
20
|
+
result.unpack packing
|
21
|
+
end
|
22
|
+
|
23
|
+
def decrypt key, data
|
24
|
+
cipher.reset
|
25
|
+
cipher.padding = 0
|
26
|
+
cipher.decrypt
|
27
|
+
cipher.key = key.pack packing
|
28
|
+
result = cipher.update data.pack(packing)
|
29
|
+
result.unpack packing
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Rmega
|
2
|
+
module Crypto
|
3
|
+
module AesCtr
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def decrypt key, nonce, data
|
7
|
+
raise "invalid nonce" if nonce.size != 4 or !nonce.respond_to?(:pack)
|
8
|
+
raise "invalid key" if key.size != 4 or !key.respond_to?(:pack)
|
9
|
+
|
10
|
+
mac = [nonce[0], nonce[1], nonce[0], nonce[1]]
|
11
|
+
enc = nil
|
12
|
+
a32 = Utils.str_to_a32 data
|
13
|
+
len = a32.size - 3
|
14
|
+
last_i = 0
|
15
|
+
|
16
|
+
(0..len).step(4) do |i|
|
17
|
+
enc = Aes.encrypt key, nonce
|
18
|
+
4.times do |m|
|
19
|
+
a32[i+m] = (a32[i+m] || 0) ^ (enc[m] || 0)
|
20
|
+
mac[m] = (mac[m] || 0) ^ (a32[i+m] || 0)
|
21
|
+
end
|
22
|
+
mac = Aes.encrypt key, mac
|
23
|
+
nonce[3] += 1
|
24
|
+
nonce[2] += 1 if nonce[3] == 0
|
25
|
+
last_i = i + 4
|
26
|
+
end
|
27
|
+
|
28
|
+
if last_i < a32.size
|
29
|
+
v = [0, 0, 0, 0]
|
30
|
+
(last_i..a32.size - 1).step(1) { |m| v[m-last_i] = a32[m] || 0 }
|
31
|
+
|
32
|
+
enc = Aes.encrypt key, nonce
|
33
|
+
4.times { |m| v[m] = v[m] ^ enc[m] }
|
34
|
+
|
35
|
+
j = data.size & 15
|
36
|
+
m = Utils.str_to_a32 Array.new(j+1).join(255.chr)+Array.new(17-j).join(0.chr)
|
37
|
+
|
38
|
+
4.times { |x| mac[x] = mac[x] ^ (v[x] & m[x]) }
|
39
|
+
|
40
|
+
mac = Aes.encrypt key, mac
|
41
|
+
|
42
|
+
(last_i..a32.size - 1).step(1) { |j| a32[j] = v[j - last_i] || 0 }
|
43
|
+
end
|
44
|
+
|
45
|
+
decrypted_data = Utils.a32_to_str(a32, data.size)
|
46
|
+
|
47
|
+
{data: decrypted_data, mac: mac}
|
48
|
+
end
|
49
|
+
|
50
|
+
def encrypt key, nonce, data
|
51
|
+
raise "invalid nonce" if nonce.size != 4 or !nonce.respond_to?(:pack)
|
52
|
+
raise "invalid key" if key.size != 4 or !key.respond_to?(:pack)
|
53
|
+
|
54
|
+
ctr = nonce.dup
|
55
|
+
mac = [ctr[0], ctr[1], ctr[0], ctr[1]]
|
56
|
+
ab32 = Utils.str_to_a32 data
|
57
|
+
len = ab32.size - 3
|
58
|
+
enc = nil
|
59
|
+
last_i = 0
|
60
|
+
|
61
|
+
(0..len).step(4) do |i|
|
62
|
+
4.times { |x| mac[x] = mac[x] ^ (ab32[i+x] || 0) }
|
63
|
+
mac = Aes.encrypt key, mac
|
64
|
+
enc = Aes.encrypt key, ctr
|
65
|
+
4.times { |x| ab32[i+x] = (ab32[i+x] || 0) ^ (enc[x] || 0) }
|
66
|
+
ctr[3] += 1
|
67
|
+
ctr[2] += 1 if ctr[3].zero?
|
68
|
+
last_i = i + 4
|
69
|
+
end
|
70
|
+
|
71
|
+
i = last_i
|
72
|
+
|
73
|
+
if i < ab32.size
|
74
|
+
v = [0, 0, 0, 0]
|
75
|
+
(i..ab32.size - 1).step(1) { |j| v[j - i] = ab32[j] || 0 }
|
76
|
+
4.times { |x| mac[x] = mac[x] ^ v[x] }
|
77
|
+
mac = Aes.encrypt key, mac
|
78
|
+
enc = Aes.encrypt key, ctr
|
79
|
+
4.times { |x| v[x] = v[x] ^ enc[x] }
|
80
|
+
(i..ab32.size - 1).step(1) { |j| ab32[j] = v[j - i] || 0 }
|
81
|
+
end
|
82
|
+
|
83
|
+
decrypted_data = Utils.a32_to_str ab32, data.size
|
84
|
+
{data: decrypted_data, mac: mac}
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Rmega
|
2
|
+
module Crypto
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def prepare_key ary
|
6
|
+
pkey = [0x93C467E3,0x7DB0C7A4,0xD1BE3F81,0x0152CB56]
|
7
|
+
65536.times do
|
8
|
+
0.step(ary.size-1, 4) do |j|
|
9
|
+
key = [0,0,0,0]
|
10
|
+
4.times do |i|
|
11
|
+
key[i] = ary[i+j] if i+j < ary.size
|
12
|
+
end
|
13
|
+
pkey = Aes.encrypt key, pkey
|
14
|
+
end
|
15
|
+
end
|
16
|
+
pkey
|
17
|
+
end
|
18
|
+
|
19
|
+
def decrypt_sid key, csid, privk
|
20
|
+
# if csid ...
|
21
|
+
t = Utils.mpi2b Utils.base64urldecode(csid)
|
22
|
+
privk = Utils.a32_to_str decrypt_key(key, Utils.base64_to_a32(privk))
|
23
|
+
rsa_privk = Array.new 4
|
24
|
+
# else if tsid (todo)
|
25
|
+
|
26
|
+
# Decompose private key
|
27
|
+
4.times do |i|
|
28
|
+
l = ((privk[0].ord * 256 + privk[1].ord + 7) >> 3) + 2
|
29
|
+
rsa_privk[i] = Utils.mpi2b privk[0..l-1]
|
30
|
+
privk = privk[l..-1]
|
31
|
+
end
|
32
|
+
|
33
|
+
# TODO - remove execjs and build the key using the ruby lib
|
34
|
+
# rsa_key = Crypto::Rsa.build_rsa_key rsa_privk
|
35
|
+
decrypted_t = Rsa.decrypt t, rsa_privk
|
36
|
+
Utils.base64urlencode Utils.b2s(decrypted_t)[0..42]
|
37
|
+
end
|
38
|
+
|
39
|
+
def encrypt_attributes key, attributes_hash
|
40
|
+
a32key = key.dup
|
41
|
+
if a32key.size > 4
|
42
|
+
a32key = [a32key[0] ^ a32key[4], a32key[1] ^ a32key[5], a32key[2] ^ a32key[6], a32key[3] ^ a32key[7]]
|
43
|
+
end
|
44
|
+
attributes_str = "MEGA#{attributes_hash.to_json}"
|
45
|
+
attributes_str << ("\x00" * (16 - (attributes_str.size % 16)))
|
46
|
+
Crypto::Aes.encrypt a32key, Utils.str_to_a32(attributes_str)
|
47
|
+
end
|
48
|
+
|
49
|
+
def decrypt_attributes key, attributes_base64
|
50
|
+
a32key = key.dup
|
51
|
+
if a32key.size > 4
|
52
|
+
a32key = [a32key[0] ^ a32key[4], a32key[1] ^ a32key[5], a32key[2] ^ a32key[6], a32key[3] ^ a32key[7]]
|
53
|
+
end
|
54
|
+
attributes = Crypto::Aes.decrypt a32key, Utils.base64_to_a32(attributes_base64)
|
55
|
+
attributes = Utils.a32_to_str attributes
|
56
|
+
JSON.parse attributes.gsub(/^MEGA/, '').rstrip
|
57
|
+
end
|
58
|
+
|
59
|
+
def prepare_key_pw password_str
|
60
|
+
prepare_key Utils.str_to_a32(password_str)
|
61
|
+
end
|
62
|
+
|
63
|
+
def stringhash aes_key, string
|
64
|
+
s32 = Utils::str_to_a32 string
|
65
|
+
h32 = [0,0,0,0]
|
66
|
+
|
67
|
+
s32.size.times { |i| h32[i & 3] ^= s32[i] }
|
68
|
+
16384.times { h32 = Aes.encrypt aes_key, h32 }
|
69
|
+
|
70
|
+
Utils::a32_to_base64 [h32[0],h32[2]]
|
71
|
+
end
|
72
|
+
|
73
|
+
def encrypt_key key, data
|
74
|
+
return Aes.encrypt(key, data) if data.size == 4
|
75
|
+
x = []
|
76
|
+
(0..data.size).step(4) do |i|
|
77
|
+
# cdata = [data[i] || 0, data[i+1] || 0, data[i+2] || 0, data[i+3] || 0]
|
78
|
+
cdata = [data[i] || 0, data[i+1] || 0, data[i+2], data[i+3]].compact
|
79
|
+
x.concat Crypto::Aes.encrypt(key, cdata)
|
80
|
+
end
|
81
|
+
x
|
82
|
+
end
|
83
|
+
|
84
|
+
def decrypt_key key, data
|
85
|
+
return Aes.decrypt(key, data) if data.size == 4
|
86
|
+
x = []
|
87
|
+
(0..data.size).step(4) do |i|
|
88
|
+
cdata = [data[i] || 0, data[i+1] || 0, data[i+2] || 0, data[i+3] || 0]
|
89
|
+
x.concat Crypto::Aes.decrypt(key, cdata)
|
90
|
+
end
|
91
|
+
x
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rmega
|
2
|
+
module Crypto
|
3
|
+
module Rsa
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def script_path
|
7
|
+
File.join File.dirname(__FILE__), 'rsa_mega.js'
|
8
|
+
end
|
9
|
+
|
10
|
+
def context
|
11
|
+
@context ||= ExecJS.compile File.read(script_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt t, privk
|
15
|
+
context.call "RSAdecrypt", t, privk[2], privk[0], privk[1], privk[3]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,455 @@
|
|
1
|
+
|
2
|
+
/* RSA public key encryption/decryption
|
3
|
+
* The following functions are (c) 2000 by John M Hanna and are
|
4
|
+
* released under the terms of the Gnu Public License.
|
5
|
+
* You must freely redistribute them with their source -- see the
|
6
|
+
* GPL for details.
|
7
|
+
* -- Latest version found at http://sourceforge.net/projects/shop-js
|
8
|
+
*
|
9
|
+
* Modifications and GnuPG multi precision integer (mpi) conversion added
|
10
|
+
* 2004 by Herbert Hanewinkel, www.haneWIN.de
|
11
|
+
*/
|
12
|
+
|
13
|
+
// --- Arbitrary Precision Math ---
|
14
|
+
// badd(a,b), bsub(a,b), bsqr(a), bmul(a,b)
|
15
|
+
// bdiv(a,b), bmod(a,b), bexpmod(g,e,m), bmodexp(g,e,m)
|
16
|
+
|
17
|
+
// bs is the shift, bm is the mask
|
18
|
+
// set single precision bits to 28
|
19
|
+
var bs=28;
|
20
|
+
var bx2=1<<bs, bm=bx2-1, bx=bx2>>1, bd=bs>>1, bdm=(1<<bd)-1;
|
21
|
+
|
22
|
+
var log2=Math.log(2);
|
23
|
+
|
24
|
+
function zeros(n)
|
25
|
+
{
|
26
|
+
var r=new Array(n);
|
27
|
+
|
28
|
+
while(n-->0) r[n]=0;
|
29
|
+
return r;
|
30
|
+
}
|
31
|
+
|
32
|
+
function zclip(r)
|
33
|
+
{
|
34
|
+
var n = r.length;
|
35
|
+
if(r[n-1]) return r;
|
36
|
+
while(n>1 && r[n-1]==0) n--;
|
37
|
+
return r.slice(0,n);
|
38
|
+
}
|
39
|
+
|
40
|
+
// returns bit length of integer x
|
41
|
+
function nbits(x)
|
42
|
+
{
|
43
|
+
var n = 1, t;
|
44
|
+
if((t=x>>>16) != 0) { x = t; n += 16; }
|
45
|
+
if((t=x>>8) != 0) { x = t; n += 8; }
|
46
|
+
if((t=x>>4) != 0) { x = t; n += 4; }
|
47
|
+
if((t=x>>2) != 0) { x = t; n += 2; }
|
48
|
+
if((t=x>>1) != 0) { x = t; n += 1; }
|
49
|
+
return n;
|
50
|
+
}
|
51
|
+
|
52
|
+
function badd(a,b)
|
53
|
+
{
|
54
|
+
var al=a.length;
|
55
|
+
var bl=b.length;
|
56
|
+
|
57
|
+
if(al < bl) return badd(b,a);
|
58
|
+
|
59
|
+
var r=new Array(al);
|
60
|
+
var c=0, n=0;
|
61
|
+
|
62
|
+
for(; n<bl; n++)
|
63
|
+
{
|
64
|
+
c+=a[n]+b[n];
|
65
|
+
r[n]=c & bm;
|
66
|
+
c>>>=bs;
|
67
|
+
}
|
68
|
+
for(; n<al; n++)
|
69
|
+
{
|
70
|
+
c+=a[n];
|
71
|
+
r[n]=c & bm;
|
72
|
+
c>>>=bs;
|
73
|
+
}
|
74
|
+
if(c) r[n]=c;
|
75
|
+
return r;
|
76
|
+
}
|
77
|
+
|
78
|
+
function bsub(a,b)
|
79
|
+
{
|
80
|
+
var al=a.length;
|
81
|
+
var bl=b.length;
|
82
|
+
|
83
|
+
if(bl > al) return [];
|
84
|
+
if(bl == al)
|
85
|
+
{
|
86
|
+
if(b[bl-1] > a[bl-1]) return [];
|
87
|
+
if(bl==1) return [a[0]-b[0]];
|
88
|
+
}
|
89
|
+
|
90
|
+
var r=new Array(al);
|
91
|
+
var c=0;
|
92
|
+
|
93
|
+
for(var n=0; n<bl; n++)
|
94
|
+
{
|
95
|
+
c+=a[n]-b[n];
|
96
|
+
r[n]=c & bm;
|
97
|
+
c>>=bs;
|
98
|
+
}
|
99
|
+
for(;n<al; n++)
|
100
|
+
{
|
101
|
+
c+=a[n];
|
102
|
+
r[n]=c & bm;
|
103
|
+
c>>=bs;
|
104
|
+
}
|
105
|
+
if(c) return [];
|
106
|
+
|
107
|
+
return zclip(r);
|
108
|
+
}
|
109
|
+
|
110
|
+
function ip(w, n, x, y, c)
|
111
|
+
{
|
112
|
+
var xl = x&bdm;
|
113
|
+
var xh = x>>bd;
|
114
|
+
|
115
|
+
var yl = y&bdm;
|
116
|
+
var yh = y>>bd;
|
117
|
+
|
118
|
+
var m = xh*yl+yh*xl;
|
119
|
+
var l = xl*yl+((m&bdm)<<bd)+w[n]+c;
|
120
|
+
w[n] = l&bm;
|
121
|
+
c = xh*yh+(m>>bd)+(l>>bs);
|
122
|
+
return c;
|
123
|
+
}
|
124
|
+
|
125
|
+
// Multiple-precision squaring, HAC Algorithm 14.16
|
126
|
+
|
127
|
+
function bsqr(x)
|
128
|
+
{
|
129
|
+
var t = x.length;
|
130
|
+
var n = 2*t;
|
131
|
+
var r = zeros(n);
|
132
|
+
var c = 0;
|
133
|
+
var i, j;
|
134
|
+
|
135
|
+
for(i = 0; i < t; i++)
|
136
|
+
{
|
137
|
+
c = ip(r,2*i,x[i],x[i],0);
|
138
|
+
for(j = i+1; j < t; j++)
|
139
|
+
{
|
140
|
+
c = ip(r,i+j,2*x[j],x[i],c);
|
141
|
+
}
|
142
|
+
r[i+t] = c;
|
143
|
+
}
|
144
|
+
|
145
|
+
return zclip(r);
|
146
|
+
}
|
147
|
+
|
148
|
+
// Multiple-precision multiplication, HAC Algorithm 14.12
|
149
|
+
|
150
|
+
function bmul(x,y)
|
151
|
+
{
|
152
|
+
var n = x.length;
|
153
|
+
var t = y.length;
|
154
|
+
var r = zeros(n+t-1);
|
155
|
+
var c, i, j;
|
156
|
+
|
157
|
+
for(i = 0; i < t; i++)
|
158
|
+
{
|
159
|
+
c = 0;
|
160
|
+
for(j = 0; j < n; j++)
|
161
|
+
{
|
162
|
+
c = ip(r,i+j,x[j],y[i],c);
|
163
|
+
}
|
164
|
+
r[i+n] = c;
|
165
|
+
}
|
166
|
+
|
167
|
+
return zclip(r);
|
168
|
+
}
|
169
|
+
|
170
|
+
function toppart(x,start,len)
|
171
|
+
{
|
172
|
+
var n=0;
|
173
|
+
while(start >= 0 && len-->0) n=n*bx2+x[start--];
|
174
|
+
return n;
|
175
|
+
}
|
176
|
+
|
177
|
+
// Multiple-precision division, HAC Algorithm 14.20
|
178
|
+
|
179
|
+
function bdiv(a,b)
|
180
|
+
{
|
181
|
+
var n=a.length-1;
|
182
|
+
var t=b.length-1;
|
183
|
+
var nmt=n-t;
|
184
|
+
|
185
|
+
// trivial cases; a < b
|
186
|
+
if(n < t || n==t && (a[n]<b[n] || n>0 && a[n]==b[n] && a[n-1]<b[n-1]))
|
187
|
+
{
|
188
|
+
this.q=[0]; this.mod=a;
|
189
|
+
return this;
|
190
|
+
}
|
191
|
+
|
192
|
+
// trivial cases; q < 4
|
193
|
+
if(n==t && toppart(a,t,2)/toppart(b,t,2) <4)
|
194
|
+
{
|
195
|
+
var x=a.concat();
|
196
|
+
var qq=0;
|
197
|
+
var xx;
|
198
|
+
for(;;)
|
199
|
+
{
|
200
|
+
xx=bsub(x,b);
|
201
|
+
if(xx.length==0) break;
|
202
|
+
x=xx; qq++;
|
203
|
+
}
|
204
|
+
this.q=[qq]; this.mod=x;
|
205
|
+
return this;
|
206
|
+
}
|
207
|
+
|
208
|
+
// normalize
|
209
|
+
var shift2=Math.floor(Math.log(b[t])/log2)+1;
|
210
|
+
var shift=bs-shift2;
|
211
|
+
|
212
|
+
var x=a.concat();
|
213
|
+
var y=b.concat();
|
214
|
+
|
215
|
+
if(shift)
|
216
|
+
{
|
217
|
+
for(i=t; i>0; i--) y[i]=((y[i]<<shift) & bm) | (y[i-1] >> shift2);
|
218
|
+
y[0]=(y[0]<<shift) & bm;
|
219
|
+
if(x[n] & ((bm <<shift2) & bm))
|
220
|
+
{
|
221
|
+
x[++n]=0; nmt++;
|
222
|
+
}
|
223
|
+
for(i=n; i>0; i--) x[i]=((x[i]<<shift) & bm) | (x[i-1] >> shift2);
|
224
|
+
x[0]=(x[0]<<shift) & bm;
|
225
|
+
}
|
226
|
+
|
227
|
+
var i, j, x2;
|
228
|
+
var q=zeros(nmt+1);
|
229
|
+
var y2=zeros(nmt).concat(y);
|
230
|
+
for(;;)
|
231
|
+
{
|
232
|
+
x2=bsub(x,y2);
|
233
|
+
if(x2.length==0) break;
|
234
|
+
q[nmt]++;
|
235
|
+
x=x2;
|
236
|
+
}
|
237
|
+
|
238
|
+
var yt=y[t], top=toppart(y,t,2)
|
239
|
+
for(i=n; i>t; i--)
|
240
|
+
{
|
241
|
+
var m=i-t-1;
|
242
|
+
if(i >= x.length) q[m]=1;
|
243
|
+
else if(x[i] == yt) q[m]=bm;
|
244
|
+
else q[m]=Math.floor(toppart(x,i,2)/yt);
|
245
|
+
|
246
|
+
var topx=toppart(x,i,3);
|
247
|
+
while(q[m] * top > topx) q[m]--;
|
248
|
+
|
249
|
+
//x-=q[m]*y*b^m
|
250
|
+
y2=y2.slice(1);
|
251
|
+
x2=bsub(x,bmul([q[m]],y2));
|
252
|
+
if(x2.length==0)
|
253
|
+
{
|
254
|
+
q[m]--;
|
255
|
+
x2=bsub(x,bmul([q[m]],y2));
|
256
|
+
}
|
257
|
+
x=x2;
|
258
|
+
}
|
259
|
+
// de-normalize
|
260
|
+
if(shift)
|
261
|
+
{
|
262
|
+
for(i=0; i<x.length-1; i++) x[i]=(x[i]>>shift) | ((x[i+1] << shift2) & bm);
|
263
|
+
x[x.length-1]>>=shift;
|
264
|
+
}
|
265
|
+
|
266
|
+
this.q = zclip(q);
|
267
|
+
this.mod = zclip(x);
|
268
|
+
return this;
|
269
|
+
}
|
270
|
+
|
271
|
+
function simplemod(i,m) // returns the mod where m < 2^bd
|
272
|
+
{
|
273
|
+
var c=0, v;
|
274
|
+
for(var n=i.length-1; n>=0; n--)
|
275
|
+
{
|
276
|
+
v=i[n];
|
277
|
+
c=((v >> bd) + (c<<bd)) % m;
|
278
|
+
c=((v & bdm) + (c<<bd)) % m;
|
279
|
+
}
|
280
|
+
return c;
|
281
|
+
}
|
282
|
+
|
283
|
+
function bmod(p,m)
|
284
|
+
{
|
285
|
+
if(m.length==1)
|
286
|
+
{
|
287
|
+
if(p.length==1) return [p[0] % m[0]];
|
288
|
+
if(m[0] < bdm) return [simplemod(p,m[0])];
|
289
|
+
}
|
290
|
+
|
291
|
+
var r=bdiv(p,m);
|
292
|
+
return r.mod;
|
293
|
+
}
|
294
|
+
|
295
|
+
// Barrett's modular reduction, HAC Algorithm 14.42
|
296
|
+
|
297
|
+
function bmod2(x,m,mu)
|
298
|
+
{
|
299
|
+
var xl=x.length - (m.length << 1);
|
300
|
+
if(xl > 0) return bmod2(x.slice(0,xl).concat(bmod2(x.slice(xl),m,mu)),m,mu);
|
301
|
+
|
302
|
+
var ml1=m.length+1, ml2=m.length-1,rr;
|
303
|
+
//var q1=x.slice(ml2)
|
304
|
+
//var q2=bmul(q1,mu)
|
305
|
+
var q3=bmul(x.slice(ml2),mu).slice(ml1);
|
306
|
+
var r1=x.slice(0,ml1);
|
307
|
+
var r2=bmul(q3,m).slice(0,ml1);
|
308
|
+
var r=bsub(r1,r2);
|
309
|
+
|
310
|
+
if(r.length==0)
|
311
|
+
{
|
312
|
+
r1[ml1]=1;
|
313
|
+
r=bsub(r1,r2);
|
314
|
+
}
|
315
|
+
for(var n=0;;n++)
|
316
|
+
{
|
317
|
+
rr=bsub(r,m);
|
318
|
+
if(rr.length==0) break;
|
319
|
+
r=rr;
|
320
|
+
if(n>=3) return bmod2(r,m,mu);
|
321
|
+
}
|
322
|
+
return r;
|
323
|
+
}
|
324
|
+
|
325
|
+
// Modular exponentiation, HAC Algorithm 14.79
|
326
|
+
|
327
|
+
function bexpmod(g,e,m)
|
328
|
+
{
|
329
|
+
var a = g.concat();
|
330
|
+
var l = e.length-1;
|
331
|
+
var n = nbits(e[l])-2;
|
332
|
+
|
333
|
+
for(; l >= 0; l--)
|
334
|
+
{
|
335
|
+
for(; n >= 0; n-=1)
|
336
|
+
{
|
337
|
+
a=bmod(bsqr(a),m);
|
338
|
+
if(e[l] & (1<<n)) a=bmod(bmul(a,g),m);
|
339
|
+
}
|
340
|
+
n = bs-1;
|
341
|
+
}
|
342
|
+
return a;
|
343
|
+
}
|
344
|
+
|
345
|
+
// Modular exponentiation using Barrett reduction
|
346
|
+
|
347
|
+
function bmodexp(g,e,m)
|
348
|
+
{
|
349
|
+
var a=g.concat();
|
350
|
+
var l=e.length-1;
|
351
|
+
var n=m.length*2;
|
352
|
+
var mu=zeros(n+1);
|
353
|
+
mu[n]=1;
|
354
|
+
mu=bdiv(mu,m).q;
|
355
|
+
|
356
|
+
n = nbits(e[l])-2;
|
357
|
+
|
358
|
+
for(; l >= 0; l--)
|
359
|
+
{
|
360
|
+
for(; n >= 0; n-=1)
|
361
|
+
{
|
362
|
+
a=bmod2(bsqr(a),m, mu);
|
363
|
+
if(e[l] & (1<<n)) a=bmod2(bmul(a,g),m, mu);
|
364
|
+
}
|
365
|
+
n = bs-1;
|
366
|
+
}
|
367
|
+
return a;
|
368
|
+
}
|
369
|
+
|
370
|
+
// -----------------------------------------------------
|
371
|
+
// Compute s**e mod m for RSA public key operation
|
372
|
+
|
373
|
+
function RSAencrypt(s, e, m) { return bexpmod(s,e,m); }
|
374
|
+
|
375
|
+
// Compute m**d mod p*q for RSA private key operations.
|
376
|
+
|
377
|
+
function RSAdecrypt(m, d, p, q, u)
|
378
|
+
{
|
379
|
+
var xp = bmodexp(bmod(m,p), bmod(d,bsub(p,[1])), p);
|
380
|
+
var xq = bmodexp(bmod(m,q), bmod(d,bsub(q,[1])), q);
|
381
|
+
|
382
|
+
var t=bsub(xq,xp);
|
383
|
+
if(t.length==0)
|
384
|
+
{
|
385
|
+
t=bsub(xp,xq);
|
386
|
+
t=bmod(bmul(t, u), q);
|
387
|
+
t=bsub(q,t);
|
388
|
+
}
|
389
|
+
else
|
390
|
+
{
|
391
|
+
t=bmod(bmul(t, u), q);
|
392
|
+
}
|
393
|
+
return badd(bmul(t,p), xp);
|
394
|
+
}
|
395
|
+
|
396
|
+
// -----------------------------------------------------------------
|
397
|
+
// conversion functions: num array <-> multi precision integer (mpi)
|
398
|
+
// mpi: 2 octets with length in bits + octets in big endian order
|
399
|
+
|
400
|
+
function mpi2b(s)
|
401
|
+
{
|
402
|
+
var bn=1, r=[0], rn=0, sb=256;
|
403
|
+
var c, sn=s.length;
|
404
|
+
if(sn < 2) return 0;
|
405
|
+
|
406
|
+
var len=(sn-2)*8;
|
407
|
+
var bits=s.charCodeAt(0)*256+s.charCodeAt(1);
|
408
|
+
if(bits > len || bits < len-8) return 0;
|
409
|
+
|
410
|
+
for(var n=0; n<len; n++)
|
411
|
+
{
|
412
|
+
if((sb<<=1) > 255)
|
413
|
+
{
|
414
|
+
sb=1; c=s.charCodeAt(--sn);
|
415
|
+
}
|
416
|
+
if(bn > bm)
|
417
|
+
{
|
418
|
+
bn=1;
|
419
|
+
r[++rn]=0;
|
420
|
+
}
|
421
|
+
if(c & sb) r[rn]|=bn;
|
422
|
+
bn<<=1;
|
423
|
+
}
|
424
|
+
return r;
|
425
|
+
}
|
426
|
+
|
427
|
+
function b2mpi(b)
|
428
|
+
{
|
429
|
+
var bn=1, bc=0, r=[0], rb=1, rn=0;
|
430
|
+
var bits=b.length*bs;
|
431
|
+
var n, rr='';
|
432
|
+
|
433
|
+
for(n=0; n<bits; n++)
|
434
|
+
{
|
435
|
+
if(b[bc] & bn) r[rn]|=rb;
|
436
|
+
if((rb<<=1) > 255)
|
437
|
+
{
|
438
|
+
rb=1; r[++rn]=0;
|
439
|
+
}
|
440
|
+
if((bn<<=1) > bm)
|
441
|
+
{
|
442
|
+
bn=1; bc++;
|
443
|
+
}
|
444
|
+
}
|
445
|
+
|
446
|
+
while(rn && r[rn]==0) rn--;
|
447
|
+
|
448
|
+
bn=256;
|
449
|
+
for(bits=8; bits>0; bits--) if(r[rn] & (bn>>=1)) break;
|
450
|
+
bits+=rn*8;
|
451
|
+
|
452
|
+
rr+=String.fromCharCode(bits/256)+String.fromCharCode(bits%256);
|
453
|
+
if(bits) for(n=rn; n>=0; n--) rr+=String.fromCharCode(r[n]);
|
454
|
+
return rr;
|
455
|
+
}
|