-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for installing JavaCard applets. Finally.
- Loading branch information
Victor Costan
committed
Nov 1, 2009
1 parent
33aacc9
commit 94774a0
Showing
17 changed files
with
967 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Loads JavaCard CAP files. | ||
# | ||
# Author:: Victor Costan | ||
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology | ||
# License:: MIT | ||
|
||
require 'zip/zip' | ||
|
||
# :nodoc: namespace | ||
module Smartcard::Gp | ||
|
||
|
||
# Logic for loading JavaCard CAP files. | ||
module CapLoader | ||
# Loads a CAP file. | ||
# | ||
# Returns a hash mapping component names to component data. | ||
def self.load_cap(cap_file) | ||
components = {} | ||
Zip::ZipFile.open(cap_file) do |file| | ||
file.each do |entry| | ||
data = entry.get_input_stream { |io| io.read } | ||
offset = 0 | ||
while offset < data.length | ||
tag = TAG_NAMES[data[offset, 1].unpack('C').first] | ||
length = data[offset + 1, 2].unpack('n').first | ||
value = data[offset + 3, length] | ||
components[tag] = value | ||
offset += 3 + length | ||
end | ||
end | ||
end | ||
components | ||
end | ||
|
||
# Serializes CAP components for on-card loading. | ||
# | ||
# Returns an array of bytes. | ||
def self.serialize_components(components) | ||
[:header, :directory, :import, :applet, :class, :method, :static_field, | ||
:export, :constant_pool, :reference_location].map { |name| | ||
tag = TAG_NAMES.keys.find { |k| TAG_NAMES[k] == name } | ||
if components[name] | ||
length = [components[name].length].pack('n').unpack('C*') | ||
data = components[name].unpack('C*') | ||
[tag, length, data] | ||
else | ||
[] | ||
end | ||
}.flatten | ||
end | ||
|
||
# Parses the Applet section in a CAP file, obtaining applet AIDs. | ||
# | ||
# Returns an array of hashes, one hash per applet. The hash has a key +:aid+ | ||
# that contains the applet's AID. | ||
def self.parse_applets(components) | ||
applets = [] | ||
return applets unless section = components[:applet] | ||
offset = 1 | ||
section[0].times do | ||
aid_length = section[offset] | ||
install_method = section[offset + 1 + aid_length, 2].unpack('n').first | ||
applets << { :aid => section[offset + 1, aid_length].unpack('C*'), | ||
:install_method => install_method } | ||
offset += 3 + aid_length | ||
end | ||
applets | ||
end | ||
|
||
# Loads a CAP file and serializes its components for on-card loading. | ||
# | ||
# Returns an array of bytes. | ||
def self.cap_load_data(cap_file) | ||
components = load_cap cap_file | ||
{ :data => serialize_components(components), | ||
:applets => parse_applets(components) } | ||
end | ||
|
||
# Maps numeric tags to tag names. | ||
TAG_NAMES = { | ||
1 => :header, 2 => :directory, 3 => :applet, 4 => :import, | ||
5 => :constant_pool, 6 => :class, 7 => :method, 8 => :static_field, | ||
9 => :reference_location, 10 => :export, 11 => :descriptor, 12 => :debug | ||
} | ||
end # module Smartcard::Gp::CapLoader | ||
|
||
end # namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# DES and 3DES encryption and MAC logic for GlobalPlatform secure channels. | ||
# | ||
# Author:: Victor Costan | ||
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology | ||
# License:: MIT | ||
|
||
require 'openssl' | ||
|
||
# :nodoc: namespace | ||
module Smartcard::Gp | ||
|
||
|
||
# DES and 3DES encryption and MAC logic for GlobalPlatform secure channels. | ||
module Des | ||
# Generates random bytes for session nonces. | ||
# | ||
# Args: | ||
# bytes:: how many bytes are desired | ||
# | ||
# Returns a string of random bytes. | ||
def self.random_bytes(bytes) | ||
OpenSSL::Random.random_bytes bytes | ||
end | ||
|
||
# Perform DES or 3DES encryption. | ||
# | ||
# Args: | ||
# key:: the encryption key to be used (8-byte or 16-byte) | ||
# data:: the data to be encrypted or decrypted | ||
# iv:: initialization vector | ||
# decrypt:: if +false+ performs encryption, otherwise performs decryption | ||
# | ||
# Returns the encrypted / decrypted data. | ||
def self.crypt(key, data, iv = nil, decrypt = false) | ||
cipher_name = key.length == 8 ? 'DES-CBC' : 'DES-EDE-CBC' | ||
cipher = OpenSSL::Cipher::Cipher.new cipher_name | ||
decrypt ? cipher.decrypt : cipher.encrypt | ||
cipher.key = key | ||
cipher.iv = iv || ("\x00" * 8) | ||
cipher.padding = 0 | ||
crypted = cipher.update data | ||
crypted += cipher.final | ||
crypted | ||
end | ||
|
||
# Computes a MAC using DES mixed with 3DES. | ||
def self.mac_retail(key, data, iv = nil) | ||
# Output transformation: add 80, then 00 until it's block-sized. | ||
data = data + "\x80" | ||
data += "\x00" * (8 - data.length % 8) unless data.length % 8 == 0 | ||
|
||
# DES-encrypt everything except for the last block. | ||
iv = crypt(key[0, 8], data[0, data.length - 8], iv)[-8, 8] | ||
# Take the chained block and supply it to a 3DES-encryption. | ||
crypt(key, data[-8, 8], iv) | ||
end | ||
|
||
def self.mac_3des(key, data) | ||
# Output transformation: add 80, then 00 until it's block-sized. | ||
data = data + "\x80" | ||
data += "\x00" * (8 - data.length % 8) unless data.length % 8 == 0 | ||
|
||
# The MAC is the last block from 3DES-encrypting the data. | ||
crypt(key, data)[-8, 8] | ||
end | ||
end # module Smartcard::Gp::Des | ||
|
||
end # namespace |
Oops, something went wrong.