imobile 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +2 -0
- data/Manifest +4 -0
- data/Rakefile +6 -0
- data/imobile.gemspec +5 -5
- data/lib/imobile.rb +1 -0
- data/lib/imobile/crypto_app_fprint.rb +120 -0
- data/test/crypto_app_fprint_test.rb +39 -0
- data/test/validate_receipt_test.rb +4 -2
- data/testdata/device_attributes.yml +8 -0
- metadata +8 -3
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
CHANGELOG
|
2
|
+
imobile.gemspec
|
3
|
+
lib/imobile/crypto_app_fprint.rb
|
2
4
|
lib/imobile/validate_receipt.rb
|
3
5
|
lib/imobile.rb
|
4
6
|
LICENSE
|
5
7
|
Manifest
|
6
8
|
Rakefile
|
7
9
|
README
|
10
|
+
test/crypto_app_fprint_test.rb
|
8
11
|
test/validate_receipt_test.rb
|
12
|
+
testdata/device_attributes.yml
|
9
13
|
testdata/forged_sandbox_receipt
|
10
14
|
testdata/valid_sandbox_receipt
|
data/Rakefile
CHANGED
data/imobile.gemspec
CHANGED
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{imobile}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Victor Costan"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-24}
|
10
10
|
s.description = %q{Library for servers backing iPhone applications.}
|
11
11
|
s.email = %q{victor@zergling.net}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "README"]
|
13
|
-
s.files = ["CHANGELOG", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/validate_receipt_test.rb", "testdata/
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/imobile/crypto_app_fprint.rb", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "README"]
|
13
|
+
s.files = ["CHANGELOG", "imobile.gemspec", "lib/imobile/crypto_app_fprint.rb", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/crypto_app_fprint_test.rb", "test/validate_receipt_test.rb", "testdata/device_attributes.yml", "testdata/forged_sandbox_receipt", "testdata/valid_sandbox_receipt"]
|
14
14
|
s.homepage = %q{http://github.com/costan/imobile}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Imobile", "--main", "README"]
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = %q{zerglings}
|
18
18
|
s.rubygems_version = %q{1.3.5}
|
19
19
|
s.summary = %q{Library for servers backing iPhone applications.}
|
20
|
-
s.test_files = ["test/validate_receipt_test.rb"]
|
20
|
+
s.test_files = ["test/crypto_app_fprint_test.rb", "test/validate_receipt_test.rb"]
|
21
21
|
|
22
22
|
if s.respond_to? :specification_version then
|
23
23
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/lib/imobile.rb
CHANGED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Application integrity finger-printing used by ZergSupport's CryptoSupport.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Zergling.Net
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'digest/sha2'
|
9
|
+
require 'set'
|
10
|
+
require 'openssl'
|
11
|
+
|
12
|
+
|
13
|
+
# :nodoc: namespace
|
14
|
+
module Imobile
|
15
|
+
|
16
|
+
# An iPhone application's finger-print, as implemented in CryptoSupport.
|
17
|
+
#
|
18
|
+
# Args:
|
19
|
+
# device_or_hash:: a Hash or ActiveRecord model representing the result of
|
20
|
+
# calling [ZNDeviceFprint deviceAttributes] on the iMobile
|
21
|
+
# device
|
22
|
+
# binary_path:: path to the application's binary (executable file)
|
23
|
+
# corresponding to the application version on the device
|
24
|
+
# (indicated by :app_version in the device attributes)
|
25
|
+
#
|
26
|
+
# Returns a finger-print that should prove the application's integrity. The
|
27
|
+
# finger-print is a string consisting of printable characters.
|
28
|
+
def self.crypto_app_fprint(device_or_hash, binary_path)
|
29
|
+
CryptoSupportAppFprint.app_fprint device_or_hash, binary_path
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Implementation details for crypto_app_fprint.
|
34
|
+
module CryptoSupportAppFprint
|
35
|
+
# The finger-print for a device's attributes, as implemented in CryptoSupport.
|
36
|
+
#
|
37
|
+
# The device attributes should be passed in a Hash that represents the result
|
38
|
+
# of calling [ZNDeviceFprint deviceAttributes] on the iMobile device.
|
39
|
+
#
|
40
|
+
# The finger-print is returned as a raw string (no hex-formatting).
|
41
|
+
# In particular, the returned finger-print is suitable to be used as a key or
|
42
|
+
# IV for AES-128.
|
43
|
+
#
|
44
|
+
# The code mirrors the reference code in ZergSupport's test suite.
|
45
|
+
def self.device_fprint(device_attributes)
|
46
|
+
Digest::MD5.digest device_fprint_data(device_attributes)
|
47
|
+
end
|
48
|
+
|
49
|
+
# The finger-print for a device's attributes, as implemented in CryptoSupport.
|
50
|
+
#
|
51
|
+
# This method resembles device_fprint, but returns the finger-print in a
|
52
|
+
# hex-formatted string, so that it can be used by Web services.
|
53
|
+
def self.hex_device_fprint(device_attributes)
|
54
|
+
device_fprint(device_attributes).unpack('C*').map {|c| '%02x' % c}.join('')
|
55
|
+
end
|
56
|
+
|
57
|
+
# The device data used for device finger-printing in CryptoSupport.
|
58
|
+
#
|
59
|
+
# The device attributes should be passed in a Hash that represents the result
|
60
|
+
# of calling [ZNDeviceFprint deviceAttributes] on the iMobile device.
|
61
|
+
def self.device_fprint_data(device_attributes)
|
62
|
+
attrs = device_fprint_attributes
|
63
|
+
keys = device_attributes.keys.select { |k| attrs.include? k.to_s }
|
64
|
+
'D|' + keys.sort.map { |k| device_attributes[k] }.join('|')
|
65
|
+
end
|
66
|
+
|
67
|
+
# The device attributes included in the finger-printing operation.
|
68
|
+
def self.device_fprint_attributes
|
69
|
+
Set.new(['app_id', 'app_version', 'app_provisioning', 'hardware_model',
|
70
|
+
'os_name', 'os_version', 'unique_id'])
|
71
|
+
end
|
72
|
+
|
73
|
+
# The finger-print for a data blob, as implemented in CryptoSupport.
|
74
|
+
#
|
75
|
+
# Args:
|
76
|
+
# data_blob:: a raw string, usually the result of reading a file
|
77
|
+
# key:: 16-byte string, to be used as an AES key
|
78
|
+
# iv:: 16-byte string, to be used as an AES key
|
79
|
+
#
|
80
|
+
# The returned finger-print is a hex-formatted string.
|
81
|
+
def self.data_fprint(data_blob, key, iv = "\0" * 16)
|
82
|
+
cipher = OpenSSL::Cipher::Cipher.new 'aes-128-cbc'
|
83
|
+
cipher.encrypt
|
84
|
+
cipher.key, cipher.iv = key, iv
|
85
|
+
|
86
|
+
plain = data_blob + "\0" * ((16 - (data_blob.length & 0x0f)) & 0x0f)
|
87
|
+
crypted = cipher.update plain
|
88
|
+
Digest::SHA2.hexdigest crypted
|
89
|
+
end
|
90
|
+
|
91
|
+
# An iPhone application's finger-print, as implemented in CryptoSupport.
|
92
|
+
#
|
93
|
+
# The device attributes should be passed in a Hash that represents the result
|
94
|
+
# of calling [ZNDeviceFprint deviceAttributes] on the iMobile device. The
|
95
|
+
# manifest data should be the result of reading the application's manifest
|
96
|
+
# file (currently its executable file).
|
97
|
+
#
|
98
|
+
# The returned finger-print is a hex-formatted string.
|
99
|
+
def self.app_fprint_from_raw_data(device_attributes, manifest_data)
|
100
|
+
key = device_fprint device_attributes
|
101
|
+
iv = "\0" * 16
|
102
|
+
data_fprint manifest_data, key, iv
|
103
|
+
end
|
104
|
+
|
105
|
+
# An iPhone application's finger-print, as implemented in CryptoSupport.
|
106
|
+
def self.app_fprint(device_or_hash, binary_path)
|
107
|
+
if device_or_hash.respond_to?(:[]) and device_or_hash.respond_to?(:keys)
|
108
|
+
# Hash-like object.
|
109
|
+
device_attributes = device_or_hash
|
110
|
+
else
|
111
|
+
# ActiveRecord model.
|
112
|
+
device_attributes = device_or_hash.attributes
|
113
|
+
end
|
114
|
+
|
115
|
+
manifest_data = File.read binary_path
|
116
|
+
app_fprint_from_raw_data device_attributes, manifest_data
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end # namespace Imobile
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2009 Zergling.Net
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'imobile'
|
6
|
+
|
7
|
+
require 'time'
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'flexmock/test_unit'
|
12
|
+
|
13
|
+
|
14
|
+
class CryptoAppFprintTest < Test::Unit::TestCase
|
15
|
+
def setup
|
16
|
+
testdata_path = File.join(File.dirname(__FILE__), '..', 'testdata')
|
17
|
+
@device_attrs = File.open(File.join(testdata_path,
|
18
|
+
'device_attributes.yml')) do |f|
|
19
|
+
YAML.load f
|
20
|
+
end
|
21
|
+
|
22
|
+
@mock_binary = '1a2b3c4d5e6f7g8h' * 16384
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_device_fprint
|
26
|
+
fprint = Imobile::CryptoSupportAppFprint.hex_device_fprint @device_attrs
|
27
|
+
assert_equal '9cef1c830742fa83ad213281c1ce47b5', fprint
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_crypto_app_fprint
|
31
|
+
mock_binary_path = '/binary/path'
|
32
|
+
flexmock(File).should_receive(:read).with(mock_binary_path).
|
33
|
+
and_return(@mock_binary)
|
34
|
+
fprint = Imobile.crypto_app_fprint @device_attrs, mock_binary_path
|
35
|
+
gold_fprint =
|
36
|
+
'b5b45dec2177d095bff66dd895c624b1bc264e48575f2b39ed5456c3821c338f'
|
37
|
+
assert_equal gold_fprint, fprint
|
38
|
+
end
|
39
|
+
end
|
@@ -10,8 +10,7 @@ require 'test/unit'
|
|
10
10
|
|
11
11
|
class ValidateReceiptTest < Test::Unit::TestCase
|
12
12
|
def setup
|
13
|
-
testdata_path = File.join(File.dirname(__FILE__), '..', 'testdata')
|
14
|
-
|
13
|
+
testdata_path = File.join(File.dirname(__FILE__), '..', 'testdata')
|
15
14
|
@forged_sandbox_blob = File.read File.join(testdata_path,
|
16
15
|
'forged_sandbox_receipt')
|
17
16
|
@valid_sandbox_blob = File.read File.join(testdata_path,
|
@@ -47,4 +46,7 @@ class ValidateReceiptTest < Test::Unit::TestCase
|
|
47
46
|
Imobile.validate_receipt(@forged_sandbox_blob, :sandbox),
|
48
47
|
"Forged receipt passed validation"
|
49
48
|
end
|
49
|
+
|
50
|
+
# TODO(costan): add tests against the real servers, as soon as someone donates
|
51
|
+
# a receipt
|
50
52
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imobile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Costan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-24 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -50,22 +50,26 @@ extensions: []
|
|
50
50
|
|
51
51
|
extra_rdoc_files:
|
52
52
|
- CHANGELOG
|
53
|
+
- lib/imobile/crypto_app_fprint.rb
|
53
54
|
- lib/imobile/validate_receipt.rb
|
54
55
|
- lib/imobile.rb
|
55
56
|
- LICENSE
|
56
57
|
- README
|
57
58
|
files:
|
58
59
|
- CHANGELOG
|
60
|
+
- imobile.gemspec
|
61
|
+
- lib/imobile/crypto_app_fprint.rb
|
59
62
|
- lib/imobile/validate_receipt.rb
|
60
63
|
- lib/imobile.rb
|
61
64
|
- LICENSE
|
62
65
|
- Manifest
|
63
66
|
- Rakefile
|
64
67
|
- README
|
68
|
+
- test/crypto_app_fprint_test.rb
|
65
69
|
- test/validate_receipt_test.rb
|
70
|
+
- testdata/device_attributes.yml
|
66
71
|
- testdata/forged_sandbox_receipt
|
67
72
|
- testdata/valid_sandbox_receipt
|
68
|
-
- imobile.gemspec
|
69
73
|
has_rdoc: true
|
70
74
|
homepage: http://github.com/costan/imobile
|
71
75
|
licenses: []
|
@@ -100,4 +104,5 @@ signing_key:
|
|
100
104
|
specification_version: 3
|
101
105
|
summary: Library for servers backing iPhone applications.
|
102
106
|
test_files:
|
107
|
+
- test/crypto_app_fprint_test.rb
|
103
108
|
- test/validate_receipt_test.rb
|