epics 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/CONTRIBUTING.md +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +165 -0
- data/README.md +197 -0
- data/Rakefile +7 -0
- data/epics.gemspec +50 -0
- data/lib/epics.rb +35 -0
- data/lib/epics/cct.rb +42 -0
- data/lib/epics/cd1.rb +42 -0
- data/lib/epics/cdd.rb +42 -0
- data/lib/epics/client.rb +216 -0
- data/lib/epics/error.rb +324 -0
- data/lib/epics/generic_request.rb +99 -0
- data/lib/epics/generic_upload_request.rb +89 -0
- data/lib/epics/haa.rb +40 -0
- data/lib/epics/hia.rb +78 -0
- data/lib/epics/hpb.rb +29 -0
- data/lib/epics/hpd.rb +40 -0
- data/lib/epics/htd.rb +40 -0
- data/lib/epics/ini.rb +69 -0
- data/lib/epics/key.rb +79 -0
- data/lib/epics/mgf.rb +41 -0
- data/lib/epics/middleware/parse_ebics.rb +15 -0
- data/lib/epics/middleware/xmlsig.rb +18 -0
- data/lib/epics/ptk.rb +52 -0
- data/lib/epics/response.rb +93 -0
- data/lib/epics/signer.rb +40 -0
- data/lib/epics/sta.rb +52 -0
- data/lib/epics/version.rb +3 -0
- data/lib/letter/ini.erb +231 -0
- data/spec/client_spec.rb +98 -0
- data/spec/fixtures/a006.pem +28 -0
- data/spec/fixtures/bank_e.pem +6 -0
- data/spec/fixtures/e002.pem +28 -0
- data/spec/fixtures/x002.pem +28 -0
- data/spec/fixtures/xml/cd1.xml +87 -0
- data/spec/fixtures/xml/ebics_business_nok.xml +21 -0
- data/spec/fixtures/xml/ebics_technical_nok.xml +12 -0
- data/spec/fixtures/xml/hia.xml +2 -0
- data/spec/fixtures/xml/hia_request_order_data.xml +2 -0
- data/spec/fixtures/xml/hpb.xml +34 -0
- data/spec/fixtures/xml/hpb_request.xml +34 -0
- data/spec/fixtures/xml/hpb_response.xml +21 -0
- data/spec/fixtures/xml/hpb_response_order.xml +22 -0
- data/spec/fixtures/xml/htd_order_data.xml +153 -0
- data/spec/fixtures/xml/ini.xml +2 -0
- data/spec/fixtures/xml/signature_pub_key_order_data.xml +2 -0
- data/spec/fixtures/xml/upload_init_response.xml +31 -0
- data/spec/hpb_spec.rb +15 -0
- data/spec/key_spec.rb +35 -0
- data/spec/mgf_spec.rb +36 -0
- data/spec/middleware/parse_ebics_spec.rb +18 -0
- data/spec/orders/cct_spec.rb +17 -0
- data/spec/orders/cd1_spec.rb +17 -0
- data/spec/orders/cdd_spec.rb +17 -0
- data/spec/orders/haa_spec.rb +11 -0
- data/spec/orders/hia_spec.rb +34 -0
- data/spec/orders/hpb_spec.rb +11 -0
- data/spec/orders/hpd_spec.rb +11 -0
- data/spec/orders/htd_spec.rb +11 -0
- data/spec/orders/ini_spec.rb +36 -0
- data/spec/orders/ptk_spec.rb +11 -0
- data/spec/orders/sta_spec.rb +11 -0
- data/spec/response_spec.rb +34 -0
- data/spec/signer_spec.rb +34 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/ebics_matcher.rb +22 -0
- data/spec/xsd/ebics_H004.xsd +11 -0
- data/spec/xsd/ebics_hev.xsd +135 -0
- data/spec/xsd/ebics_keymgmt_request_H004.xsd +543 -0
- data/spec/xsd/ebics_keymgmt_response_H004.xsd +137 -0
- data/spec/xsd/ebics_orders_H004.xsd +1892 -0
- data/spec/xsd/ebics_request_H004.xsd +355 -0
- data/spec/xsd/ebics_response_H004.xsd +166 -0
- data/spec/xsd/ebics_signature.xsd +217 -0
- data/spec/xsd/ebics_types_H004.xsd +2426 -0
- data/spec/xsd/xmldsig-core-schema.xsd +318 -0
- metadata +319 -0
data/lib/epics/key.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
class Epics::Key
|
2
|
+
attr_accessor :key
|
3
|
+
|
4
|
+
def initialize(encoded_key, passphrase = nil)
|
5
|
+
if encoded_key.kind_of?(OpenSSL::PKey::RSA)
|
6
|
+
self.key = encoded_key
|
7
|
+
else
|
8
|
+
self.key = OpenSSL::PKey::RSA.new(encoded_key)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
###
|
13
|
+
# concat the exponent and modulus (hex representation) with a single whitespace
|
14
|
+
# remove leading zeros from both
|
15
|
+
# calculate digest (SHA256)
|
16
|
+
# encode as Base64
|
17
|
+
####
|
18
|
+
def public_digest
|
19
|
+
c = [ e.gsub(/^0*/,''), n.gsub(/^0*/,'') ].map(&:downcase).join(" ")
|
20
|
+
|
21
|
+
Base64.encode64(digester.digest(c)).strip
|
22
|
+
end
|
23
|
+
|
24
|
+
def n
|
25
|
+
self.key.n.to_s(16)
|
26
|
+
end
|
27
|
+
|
28
|
+
def e
|
29
|
+
self.key.e.to_s(16)
|
30
|
+
end
|
31
|
+
|
32
|
+
def sign(msg, salt = OpenSSL::Random.random_bytes(32) )
|
33
|
+
Base64.encode64(mod_pow(OpenSSL::BN.new(emsa_pss(msg, salt).to_s, 2), self.key.d, self.key.n).to_s(2)).gsub("\n", "")
|
34
|
+
end
|
35
|
+
|
36
|
+
def recover(msg)
|
37
|
+
mod_pow(OpenSSL::BN.new(msg.to_s, 2), self.key.e, self.key.n).to_s(2)
|
38
|
+
end
|
39
|
+
|
40
|
+
def digester
|
41
|
+
@digester ||= OpenSSL::Digest::SHA256.new
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
##
|
47
|
+
# http://de.wikipedia.org/wiki/Probabilistic_Signature_Scheme
|
48
|
+
##
|
49
|
+
def emsa_pss(msg, salt)
|
50
|
+
m_tick_hash = digester.digest [("\x00" * 8), digester.digest(msg), salt].join
|
51
|
+
|
52
|
+
ps = "\x00" * 190
|
53
|
+
db = [ps, "\x01", salt].join
|
54
|
+
|
55
|
+
db_mask = Epics::MGF1.new.generate(m_tick_hash, db.size)
|
56
|
+
masked_db = Epics::MGF1.new.xor(db, db_mask)
|
57
|
+
|
58
|
+
masked_db_msb = OpenSSL::BN.new(masked_db[0], 2).to_i.to_s(2).rjust(8, "0")
|
59
|
+
masked_db_msb[0] = "0"
|
60
|
+
|
61
|
+
masked_db[0] = OpenSSL::BN.new(masked_db_msb.to_i(2).to_s).to_s(2)
|
62
|
+
|
63
|
+
[masked_db, m_tick_hash, ["BC"].pack("H*") ].join
|
64
|
+
end
|
65
|
+
|
66
|
+
def mod_pow(base, power, mod)
|
67
|
+
base = base.to_i
|
68
|
+
power = power.to_i
|
69
|
+
mod = mod.to_i
|
70
|
+
result = 1
|
71
|
+
while power > 0
|
72
|
+
result = (result * base) % mod if power & 1 == 1
|
73
|
+
base = (base * base) % mod
|
74
|
+
power >>= 1
|
75
|
+
end
|
76
|
+
OpenSSL::BN.new(result.to_s)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/lib/epics/mgf.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
class Epics::MGF1
|
2
|
+
def initialize(digest = OpenSSL::Digest::SHA256)
|
3
|
+
@digest = digest.new
|
4
|
+
@hlen = 32
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate(seed, masklen)
|
8
|
+
if masklen > (2 << 31) * @hlen
|
9
|
+
raise ArgumentError, "mask too long"
|
10
|
+
end
|
11
|
+
t = ""
|
12
|
+
divceil(masklen, @hlen).times do |counter|
|
13
|
+
t += @digest.digest(seed + i2osp(counter, 4))
|
14
|
+
end
|
15
|
+
t[0, masklen]
|
16
|
+
end
|
17
|
+
|
18
|
+
def i2osp(x, len)
|
19
|
+
if x >= 256 ** len
|
20
|
+
raise ArgumentError, "integer too large"
|
21
|
+
end
|
22
|
+
[x].pack("N").gsub(/^\x00+/, '').rjust(len, "\x00")
|
23
|
+
end
|
24
|
+
|
25
|
+
def divceil(a, b)
|
26
|
+
(a + b - 1) / b
|
27
|
+
end
|
28
|
+
|
29
|
+
def xor(a, b)
|
30
|
+
if a.size != b.size
|
31
|
+
raise ArgumentError, "different length for a and b"
|
32
|
+
end
|
33
|
+
a = a.unpack('C*')
|
34
|
+
b = b.unpack('C*')
|
35
|
+
a.size.times do |idx|
|
36
|
+
a[idx] ^= b[idx]
|
37
|
+
end
|
38
|
+
a.pack("C*")
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Epics::ParseEbics < Faraday::Middleware
|
2
|
+
|
3
|
+
def initialize(app = nil, options = {})
|
4
|
+
super(app)
|
5
|
+
@client = options[:client]
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@app.call(env).on_complete do |env|
|
10
|
+
env[:body] = ::Epics::Response.new(@client, env[:body])
|
11
|
+
raise Epics::Error::TechnicalError.new(env[:body].technical_code) if env[:body].technical_error?
|
12
|
+
raise Epics::Error::BusinessError.new(env[:body].business_code) if env[:body].business_error?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Epics::XMLSIG < Faraday::Middleware
|
2
|
+
|
3
|
+
def initialize(app, options = {})
|
4
|
+
super(app)
|
5
|
+
@client = options[:client]
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@signer = Epics::Signer.new(@client, env["body"])
|
10
|
+
@signer.digest!
|
11
|
+
@signer.sign!
|
12
|
+
|
13
|
+
env["body"] = @signer.doc.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/epics/ptk.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class Epics::PTK < Epics::GenericRequest
|
2
|
+
attr_accessor :from, :to
|
3
|
+
|
4
|
+
def initialize(client, from, to)
|
5
|
+
super(client)
|
6
|
+
self.from = from
|
7
|
+
self.to = to
|
8
|
+
end
|
9
|
+
|
10
|
+
def header
|
11
|
+
{
|
12
|
+
:@authenticate => true,
|
13
|
+
static: {
|
14
|
+
"HostID" => host_id,
|
15
|
+
"Nonce" => nonce,
|
16
|
+
"Timestamp" => timestamp,
|
17
|
+
"PartnerID" => partner_id,
|
18
|
+
"UserID" => user_id,
|
19
|
+
"Product" => {
|
20
|
+
:@Language => "de",
|
21
|
+
:content! => "EPICS - a ruby ebics kernel"
|
22
|
+
},
|
23
|
+
"OrderDetails" => {
|
24
|
+
"OrderType" => "PTK",
|
25
|
+
"OrderAttribute" => "DZHNN",
|
26
|
+
"StandardOrderParams" => {
|
27
|
+
"DateRange" => {
|
28
|
+
"Start" => from,
|
29
|
+
"End" => to
|
30
|
+
}
|
31
|
+
}
|
32
|
+
},
|
33
|
+
"BankPubKeyDigests" => {
|
34
|
+
"Authentication" => {
|
35
|
+
:@Version => "X002",
|
36
|
+
:@Algorithm => "http://www.w3.org/2001/04/xmlenc#sha256",
|
37
|
+
:content! => client.bank_x.public_digest
|
38
|
+
},
|
39
|
+
"Encryption" => {
|
40
|
+
:@Version => "E002",
|
41
|
+
:@Algorithm => "http://www.w3.org/2001/04/xmlenc#sha256",
|
42
|
+
:content! => client.bank_e.public_digest
|
43
|
+
}
|
44
|
+
},
|
45
|
+
"SecurityMedium" => "0000"
|
46
|
+
},
|
47
|
+
"mutable" => {
|
48
|
+
"TransactionPhase" => "Initialisation"
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class Epics::Response
|
2
|
+
attr_accessor :doc
|
3
|
+
attr_accessor :client
|
4
|
+
|
5
|
+
def initialize(client, xml)
|
6
|
+
self.doc = Nokogiri::XML.parse(xml)
|
7
|
+
self.client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def technical_error?
|
11
|
+
technical_code != "000000"
|
12
|
+
end
|
13
|
+
|
14
|
+
def technical_code
|
15
|
+
doc.xpath("//xmlns:header/xmlns:mutable/xmlns:ReturnCode").text
|
16
|
+
end
|
17
|
+
|
18
|
+
def business_error?
|
19
|
+
business_code != "000000" && business_code != ""
|
20
|
+
end
|
21
|
+
|
22
|
+
def business_code
|
23
|
+
doc.xpath("//xmlns:body/xmlns:ReturnCode").text
|
24
|
+
end
|
25
|
+
|
26
|
+
def ok?
|
27
|
+
!technical_error? & !business_error?
|
28
|
+
end
|
29
|
+
|
30
|
+
def return_code
|
31
|
+
doc.xpath("//xmlns:ReturnCode").last.content
|
32
|
+
rescue NoMethodError
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def report_text
|
37
|
+
doc.xpath("//xmlns:ReportText").first.content
|
38
|
+
end
|
39
|
+
|
40
|
+
def transaction_id
|
41
|
+
doc.xpath("//xmlns:TransactionID").first.content
|
42
|
+
end
|
43
|
+
|
44
|
+
def digest_valid?
|
45
|
+
authenticated = doc.xpath("//*[@authenticate='true']").map(&:canonicalize).join
|
46
|
+
digest_value = doc.xpath("//ds:DigestValue").first
|
47
|
+
|
48
|
+
digest = Base64.encode64(digester.digest(authenticated)).strip
|
49
|
+
|
50
|
+
digest == digest_value.content
|
51
|
+
end
|
52
|
+
|
53
|
+
def signature_valid?
|
54
|
+
signature = doc.xpath("//ds:SignedInfo").first.canonicalize
|
55
|
+
signature_value = doc.xpath("//ds:SignatureValue").first
|
56
|
+
|
57
|
+
client.bank_x.key.verify(digester, Base64.decode64(signature_value.content), signature)
|
58
|
+
end
|
59
|
+
|
60
|
+
def public_digest_valid?
|
61
|
+
encryption_pub_key_digest = doc.xpath("//xmlns:EncryptionPubKeyDigest").first
|
62
|
+
|
63
|
+
client.e.public_digest == encryption_pub_key_digest.content
|
64
|
+
end
|
65
|
+
|
66
|
+
def order_data
|
67
|
+
order_data_encrypted = Base64.decode64(doc.xpath("//xmlns:OrderData").first.content)
|
68
|
+
|
69
|
+
data = (cipher.update(order_data_encrypted) + cipher.final)
|
70
|
+
|
71
|
+
Zlib::Inflate.new.inflate(data)
|
72
|
+
end
|
73
|
+
|
74
|
+
def cipher
|
75
|
+
cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
|
76
|
+
|
77
|
+
cipher.decrypt
|
78
|
+
cipher.padding = 0
|
79
|
+
cipher.key = transaction_key
|
80
|
+
cipher
|
81
|
+
end
|
82
|
+
|
83
|
+
def transaction_key
|
84
|
+
transaction_key_encrypted = Base64.decode64(doc.xpath("//xmlns:TransactionKey").first.content)
|
85
|
+
|
86
|
+
@transaction_key ||= client.e.key.private_decrypt(transaction_key_encrypted)
|
87
|
+
end
|
88
|
+
|
89
|
+
def digester
|
90
|
+
@digester ||= OpenSSL::Digest::SHA256.new
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/epics/signer.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
class Epics::Signer
|
2
|
+
attr_accessor :doc, :client
|
3
|
+
|
4
|
+
def initialize(client, doc = nil)
|
5
|
+
self.doc = Nokogiri::XML.parse(doc) if doc
|
6
|
+
self.client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
def digest!
|
10
|
+
content_to_digest = Base64.encode64(digester.digest(doc.xpath("//*[@authenticate='true']").map(&:canonicalize).join)).strip
|
11
|
+
|
12
|
+
if digest_node
|
13
|
+
digest_node.content = content_to_digest
|
14
|
+
end
|
15
|
+
|
16
|
+
doc
|
17
|
+
end
|
18
|
+
|
19
|
+
def sign!
|
20
|
+
signature_value_node = doc.xpath("//ds:SignatureValue").first
|
21
|
+
|
22
|
+
if signature_node
|
23
|
+
signature_value_node.content = Base64.encode64(client.x.key.sign(digester, signature_node.canonicalize)).gsub(/\n/,'')
|
24
|
+
end
|
25
|
+
|
26
|
+
doc
|
27
|
+
end
|
28
|
+
|
29
|
+
def digest_node
|
30
|
+
@d ||= doc.xpath("//ds:DigestValue").first
|
31
|
+
end
|
32
|
+
|
33
|
+
def signature_node
|
34
|
+
@s ||= doc.xpath("//ds:SignedInfo").first
|
35
|
+
end
|
36
|
+
|
37
|
+
def digester
|
38
|
+
OpenSSL::Digest::SHA256.new
|
39
|
+
end
|
40
|
+
end
|
data/lib/epics/sta.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class Epics::STA < Epics::GenericRequest
|
2
|
+
attr_accessor :from, :to
|
3
|
+
|
4
|
+
def initialize(client, from, to)
|
5
|
+
super(client)
|
6
|
+
self.from = from
|
7
|
+
self.to = to
|
8
|
+
end
|
9
|
+
|
10
|
+
def header
|
11
|
+
{
|
12
|
+
:@authenticate => true,
|
13
|
+
static: {
|
14
|
+
"HostID" => host_id,
|
15
|
+
"Nonce" => nonce,
|
16
|
+
"Timestamp" => timestamp,
|
17
|
+
"PartnerID" => partner_id,
|
18
|
+
"UserID" => user_id,
|
19
|
+
"Product" => {
|
20
|
+
:@Language => "de",
|
21
|
+
:content! => "EPICS - a ruby ebics kernel"
|
22
|
+
},
|
23
|
+
"OrderDetails" => {
|
24
|
+
"OrderType" => "STA",
|
25
|
+
"OrderAttribute" => "DZHNN",
|
26
|
+
"StandardOrderParams" => {
|
27
|
+
"DateRange" => {
|
28
|
+
"Start" => from,
|
29
|
+
"End" => to
|
30
|
+
}
|
31
|
+
}
|
32
|
+
},
|
33
|
+
"BankPubKeyDigests" => {
|
34
|
+
"Authentication" => {
|
35
|
+
:@Version => "X002",
|
36
|
+
:@Algorithm => "http://www.w3.org/2001/04/xmlenc#sha256",
|
37
|
+
:content! => client.bank_x.public_digest
|
38
|
+
},
|
39
|
+
"Encryption" => {
|
40
|
+
:@Version => "E002",
|
41
|
+
:@Algorithm => "http://www.w3.org/2001/04/xmlenc#sha256",
|
42
|
+
:content! => client.bank_e.public_digest
|
43
|
+
}
|
44
|
+
},
|
45
|
+
"SecurityMedium" => "0000"
|
46
|
+
},
|
47
|
+
"mutable" => {
|
48
|
+
"TransactionPhase" => "Initialisation"
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
data/lib/letter/ini.erb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
5
|
+
<meta charset="UTF-8" />
|
6
|
+
<title>EBICS ini</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div>
|
10
|
+
<h2>EBICS-Initialisierungsbrief (INI)</h2>
|
11
|
+
<table>
|
12
|
+
<tr>
|
13
|
+
<td>
|
14
|
+
Datum
|
15
|
+
</td>
|
16
|
+
<td>
|
17
|
+
<%= Date.today.strftime("%d.%m.%Y") %>
|
18
|
+
</td>
|
19
|
+
</tr>
|
20
|
+
<tr>
|
21
|
+
<td>
|
22
|
+
Uhrzeit
|
23
|
+
</td>
|
24
|
+
<td>
|
25
|
+
<%= Time.now.strftime("%H:%M:%S") %>
|
26
|
+
</td>
|
27
|
+
</tr>
|
28
|
+
<tr>
|
29
|
+
<td>
|
30
|
+
Empfänger
|
31
|
+
</td>
|
32
|
+
<td>
|
33
|
+
<%= bankname %>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
<tr>
|
37
|
+
<td>
|
38
|
+
User-ID
|
39
|
+
</td>
|
40
|
+
<td>
|
41
|
+
<%= user_id %>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<tr>
|
45
|
+
<td>
|
46
|
+
Kunden-ID
|
47
|
+
</td>
|
48
|
+
<td>
|
49
|
+
<%= partner_id %>
|
50
|
+
</td>
|
51
|
+
</tr>
|
52
|
+
</table>
|
53
|
+
<p>Öffentlicher Schlüssel für die elektronische Unterschrift (A006)</p>
|
54
|
+
<p>Exponent (<%= a.key.e.num_bytes * 8 %> Bit):</p>
|
55
|
+
<p><code><%= a.e %></code></p>
|
56
|
+
<p>Modulus (<%= a.key.n.num_bytes * 8 %> Bit):</p>
|
57
|
+
<p><code><%= a.n.scan(/.{2}/).join(" ") %></code></p>
|
58
|
+
<p>Hash (SHA-256):</p>
|
59
|
+
<p>
|
60
|
+
<code><%= Base64.decode64(a.public_digest).unpack("H*").join.upcase.scan(/.{2}/).join(" ") %></code>
|
61
|
+
</p>
|
62
|
+
<p>Ich bestätige hiermit den obigen öffentlichen Schlüssel für meine elektronische Unterschrift.</p>
|
63
|
+
<br/>
|
64
|
+
<br/>
|
65
|
+
<br/>
|
66
|
+
<br/>
|
67
|
+
<table>
|
68
|
+
<tr>
|
69
|
+
<td>
|
70
|
+
_________________________
|
71
|
+
</td>
|
72
|
+
<td>
|
73
|
+
_________________________
|
74
|
+
</td>
|
75
|
+
<td>
|
76
|
+
_________________________
|
77
|
+
</td>
|
78
|
+
</tr>
|
79
|
+
<tr>
|
80
|
+
<td>
|
81
|
+
Ort/Datum
|
82
|
+
</td>
|
83
|
+
<td>
|
84
|
+
Name/Firma
|
85
|
+
</td>
|
86
|
+
<td>
|
87
|
+
Unterschrift
|
88
|
+
</td>
|
89
|
+
</tr>
|
90
|
+
</table>
|
91
|
+
</div>
|
92
|
+
<div style="page-break-after:always"></div>
|
93
|
+
<h2>EBICS-Initialisierungsbrief (HIA) - Seite 1/2</h2>
|
94
|
+
<table>
|
95
|
+
<tr>
|
96
|
+
<td>
|
97
|
+
Datum
|
98
|
+
</td>
|
99
|
+
<td>
|
100
|
+
<%= Date.today.strftime("%d.%m.%Y") %>
|
101
|
+
</td>
|
102
|
+
</tr>
|
103
|
+
<tr>
|
104
|
+
<td>
|
105
|
+
Uhrzeit
|
106
|
+
</td>
|
107
|
+
<td>
|
108
|
+
<%= Time.now.strftime("%H:%M:%S") %>
|
109
|
+
</td>
|
110
|
+
</tr>
|
111
|
+
<tr>
|
112
|
+
<td>
|
113
|
+
Empfänger
|
114
|
+
</td>
|
115
|
+
<td>
|
116
|
+
<%= bankname %>
|
117
|
+
</td>
|
118
|
+
</tr>
|
119
|
+
<tr>
|
120
|
+
<td>
|
121
|
+
User-ID
|
122
|
+
</td>
|
123
|
+
<td>
|
124
|
+
<%= user_id %>
|
125
|
+
</td>
|
126
|
+
</tr>
|
127
|
+
<tr>
|
128
|
+
<td>
|
129
|
+
Kunden-ID
|
130
|
+
</td>
|
131
|
+
<td>
|
132
|
+
<%= partner_id %>
|
133
|
+
</td>
|
134
|
+
</tr>
|
135
|
+
</table>
|
136
|
+
<div>
|
137
|
+
<p>Öffentlicher Authentifikationsschlüssel (X002)</p>
|
138
|
+
<p>Exponent (<%= x.key.e.num_bytes * 8 %> Bit):</p>
|
139
|
+
<p><code><%= x.e %></code></p>
|
140
|
+
<p>Modulus (<%= x.key.n.num_bytes * 8 %> Bit):</p>
|
141
|
+
<p><code><%= x.n.scan(/.{2}/).join(" ") %></code></p>
|
142
|
+
<p>Hash (SHA-256):</p>
|
143
|
+
<p>
|
144
|
+
<code><%= Base64.decode64(x.public_digest).unpack("H*").join.upcase.scan(/.{2}/).join(" ") %></code>
|
145
|
+
</p>
|
146
|
+
<p> Fortsetzung auf Seite 2 ...</p>
|
147
|
+
<div style="page-break-after:always"></div>
|
148
|
+
<h2>EBICS-Initialisierungsbrief (HIA) - Seite 2/2</h2>
|
149
|
+
<table>
|
150
|
+
<tr>
|
151
|
+
<td>
|
152
|
+
Datum
|
153
|
+
</td>
|
154
|
+
<td>
|
155
|
+
<%= Date.today.strftime("%d.%m.%Y") %>
|
156
|
+
</td>
|
157
|
+
</tr>
|
158
|
+
<tr>
|
159
|
+
<td>
|
160
|
+
Uhrzeit
|
161
|
+
</td>
|
162
|
+
<td>
|
163
|
+
<%= Time.now.strftime("%H:%M:%S") %>
|
164
|
+
</td>
|
165
|
+
</tr>
|
166
|
+
<tr>
|
167
|
+
<td>
|
168
|
+
Empfänger
|
169
|
+
</td>
|
170
|
+
<td>
|
171
|
+
<%= bankname %>
|
172
|
+
</td>
|
173
|
+
</tr>
|
174
|
+
<tr>
|
175
|
+
<td>
|
176
|
+
User-ID
|
177
|
+
</td>
|
178
|
+
<td>
|
179
|
+
<%= user_id %>
|
180
|
+
</td>
|
181
|
+
</tr>
|
182
|
+
<tr>
|
183
|
+
<td>
|
184
|
+
Kunden-ID
|
185
|
+
</td>
|
186
|
+
<td>
|
187
|
+
<%= partner_id %>
|
188
|
+
</td>
|
189
|
+
</tr>
|
190
|
+
</table>
|
191
|
+
</div>
|
192
|
+
<div>
|
193
|
+
<p>Öffentlicher Verschlüsselungsschlüssel (E002)</p>
|
194
|
+
<p>Exponent (<%= e.key.e.num_bytes * 8 %> Bit):</p>
|
195
|
+
<p><code><%= e.e %></code></p>
|
196
|
+
<p>Modulus (<%= e.key.n.num_bytes * 8 %> Bit):</p>
|
197
|
+
<p><code><%= e.n.scan(/.{2}/).join(" ") %></code></p>
|
198
|
+
<p>Hash (SHA-256):</p>
|
199
|
+
<p><code><%= Base64.decode64(e.public_digest).unpack("H*").join.upcase.scan(/.{2}/).join(" ") %></code></p>
|
200
|
+
<p>Ich bestätige hiermit die obigen öffentlichen Schlüssel für meinen EBICS-Zugang.</p>
|
201
|
+
<br/>
|
202
|
+
<br/>
|
203
|
+
<br/>
|
204
|
+
<br/>
|
205
|
+
<table>
|
206
|
+
<tr>
|
207
|
+
<td>
|
208
|
+
_________________________
|
209
|
+
</td>
|
210
|
+
<td>
|
211
|
+
_________________________
|
212
|
+
</td>
|
213
|
+
<td>
|
214
|
+
_________________________
|
215
|
+
</td>
|
216
|
+
</tr>
|
217
|
+
<tr>
|
218
|
+
<td>
|
219
|
+
Ort/Datum
|
220
|
+
</td>
|
221
|
+
<td>
|
222
|
+
Name/Firma
|
223
|
+
</td>
|
224
|
+
<td>
|
225
|
+
Unterschrift
|
226
|
+
</td>
|
227
|
+
</tr>
|
228
|
+
</table>
|
229
|
+
</div>
|
230
|
+
</body>
|
231
|
+
</html>
|