From 1420cadcec46bd094eae99e8df63677659e05dd0 Mon Sep 17 00:00:00 2001 From: Martin Bosslet Date: Sat, 2 Jun 2012 05:27:28 +0300 Subject: [PATCH 01/12] explicit https URL for rubygems --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 5868b5e..bf265ff 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source :rubygems +source 'https://rubygems.org' gem 'krypt', :path => File.expand_path('../krypt', File.dirname(__FILE__)) gem 'krypt-provider-jce', :path => File.expand_path('../krypt-provider-jce', File.dirname(__FILE__)) From b400906631c1291b4d53e0ae28bf1f7f572f0bb2 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 10 Jun 2012 14:14:39 +0530 Subject: [PATCH 02/12] Add Prototype for Cipher --- src/org/jruby/ext/krypt/provider/Cipher.java | 48 +++++++++++++++++++ .../ext/krypt/provider/KryptProvider.java | 4 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/org/jruby/ext/krypt/provider/Cipher.java diff --git a/src/org/jruby/ext/krypt/provider/Cipher.java b/src/org/jruby/ext/krypt/provider/Cipher.java new file mode 100644 index 0000000..f278dcf --- /dev/null +++ b/src/org/jruby/ext/krypt/provider/Cipher.java @@ -0,0 +1,48 @@ +/***** BEGIN LICENSE BLOCK ***** +* Version: CPL 1.0/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Common Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.eclipse.org/legal/cpl-v10.html +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Copyright (C) 2011 +* Hiroshi Nakamura +* Martin Bosslet +* +* Alternatively, the contents of this file may be used under the terms of +* either of the GNU General Public License Version 2 or later (the "GPL"), +* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the CPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the CPL, the GPL or the LGPL. + */ +package org.jruby.ext.krypt.provider; + +import java.security.InvalidKeyException; +import java.security.Key; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; + + +public interface Cipher { + + public byte [] doFinal() throws IllegalBlockSizeException, BadPaddingException; + public byte [] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException; + public void init(int opmode, Key key) throws InvalidKeyException; + public int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException; + public String getName(); + +} + diff --git a/src/org/jruby/ext/krypt/provider/KryptProvider.java b/src/org/jruby/ext/krypt/provider/KryptProvider.java index 242c762..3e2afa7 100644 --- a/src/org/jruby/ext/krypt/provider/KryptProvider.java +++ b/src/org/jruby/ext/krypt/provider/KryptProvider.java @@ -30,6 +30,7 @@ package org.jruby.ext.krypt.provider; import java.security.NoSuchAlgorithmException; +import javax.crypto.NoSuchPaddingException; /** * @@ -39,5 +40,6 @@ public interface KryptProvider { public Digest newDigestByName(String name) throws NoSuchAlgorithmException; public Digest newDigestByOid(String oid) throws NoSuchAlgorithmException; - + public Cipher newCipherByName(String name) throws NoSuchAlgorithmException, NoSuchPaddingException; + public Cipher newCipherByOid(String oid) throws NoSuchAlgorithmException, NoSuchPaddingException; } From 13f0a829ca4a6128703cb6dd1d2f9c23e11ae817 Mon Sep 17 00:00:00 2001 From: emboss Date: Fri, 29 Jun 2012 03:39:26 +0200 Subject: [PATCH 03/12] Expose Hex in Ruby --- lib/kryptcore.jar | Bin 197008 -> 198439 bytes src/org/jruby/ext/krypt/Errors.java | 4 + src/org/jruby/ext/krypt/Hex.java | 5 +- src/org/jruby/ext/krypt/KryptCoreService.java | 2 + src/org/jruby/ext/krypt/codec/RubyHex.java | 78 ++++++++++++++++++ test/scratch.rb | 25 ------ 6 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 src/org/jruby/ext/krypt/codec/RubyHex.java diff --git a/lib/kryptcore.jar b/lib/kryptcore.jar index 3001a2b2fda34225a738c6989a7fe5682fc65d98..2969a3b46ff4b95ceee5e38b892989306104b602 100644 GIT binary patch delta 12008 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 +* Martin Bosslet +* +* Alternatively, the contents of this file may be used under the terms of +* either of the GNU General Public License Version 2 or later (the "GPL"), +* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the CPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the CPL, the GPL or the LGPL. + */ +package org.jruby.ext.krypt.codec; + +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.Hex; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +/** + * + * @author Martin Bosslet + */ +public class RubyHex { + + private RubyHex() {} + + @JRubyMethod(meta = true) + public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { + try { + byte[] bytes = data.convertToString().getBytes(); + byte[] encoded = Hex.encode(bytes); + return ctx.getRuntime().newString(new ByteList(encoded, false)); + } catch (RuntimeException ex) { + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + } + + @JRubyMethod(meta = true) + public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { + try { + byte[] bytes = data.convertToString().getBytes(); + byte[] decoded = Hex.decode(bytes); + return ctx.getRuntime().newString(new ByteList(decoded, false)); + } catch (RuntimeException ex) { + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + } + + public static void createHex(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mHex = runtime.defineModuleUnder("Hex", krypt); + mHex.defineClassUnder("HexError", kryptError, kryptError.getAllocator()); + mHex.defineAnnotatedMethods(RubyHex.class); + } + +} \ No newline at end of file diff --git a/test/scratch.rb b/test/scratch.rb index 6291fa7..a70f405 100644 --- a/test/scratch.rb +++ b/test/scratch.rb @@ -4,28 +4,3 @@ require 'pp' require 'base64' -A = Class.new do - include Krypt::ASN1::Template::Sequence - asn1_integer :a -end - -B = Class.new do - include Krypt::ASN1::Template::Sequence - asn1_boolean :a -end - -C = Class.new do - include Krypt::ASN1::Template::Choice - asn1_template B, tag: 1, tagging: :EXPLICIT -end - -D = Class.new do - include Krypt::ASN1::Template::Sequence - asn1_template :b, C, tag: 2, tagging: :EXPLICIT -end - -asn1 = D.parse_der "\x30\x09\xA2\x07\xA1\x05\x30\x03\x01\x01\xFF" - -p asn1.b.value.a - - From 53750a3168c0051aa09a49afe7e14a2a339db6fc Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 3 Jul 2012 13:02:28 +0530 Subject: [PATCH 04/12] Added kryptcore lib --- .gitignore | 1 + src/org/jruby/ext/krypt/asn1/RubyBase64.java | 118 +++++++++++++++++++ src/org/jruby/ext/krypt/asn1/RubyHex.java | 118 +++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 src/org/jruby/ext/krypt/asn1/RubyBase64.java create mode 100644 src/org/jruby/ext/krypt/asn1/RubyHex.java diff --git a/.gitignore b/.gitignore index 076892e..f08721c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ pkg build.properties build_lib/jruby.jar build +lib/kryptcore.jar coverage.ec dist doc diff --git a/src/org/jruby/ext/krypt/asn1/RubyBase64.java b/src/org/jruby/ext/krypt/asn1/RubyBase64.java new file mode 100644 index 0000000..845d46c --- /dev/null +++ b/src/org/jruby/ext/krypt/asn1/RubyBase64.java @@ -0,0 +1,118 @@ +/***** BEGIN LICENSE BLOCK ***** +* Version: CPL 1.0/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Common Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.eclipse.org/legal/cpl-v10.html +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Copyright (C) 2011 +* Hiroshi Nakamura +* Martin Bosslet +* +* Alternatively, the contents of this file may be used under the terms of +* either of the GNU General Public License Version 2 or later (the "GPL"), +* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the CPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the CPL, the GPL or the LGPL. + */ +package org.jruby.ext.krypt.asn1; + +import impl.krypt.asn1.pem.PemInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.Streams; +import org.jruby.runtime.Block; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +/** + * + * @author Martin Bosslet + */ +public class RubyPem { + + private RubyPem() {} + + private static void yieldToBlock(ThreadContext ctx, IRubyObject current, String jname, int ji, Block block) { + IRubyObject name = ctx.getRuntime().newString(jname); + IRubyObject i = RubyNumeric.int2fix(ctx.getRuntime(), ji); + block.yieldSpecific(ctx, current, name, i); + } + + private static IRubyObject decodeAry(ThreadContext ctx, PemInputStream pem, Block block) throws IOException { + Ruby runtime = ctx.getRuntime(); + List ary = new ArrayList(); + byte[] bytes; + int i = 0; + + while ((bytes = Streams.consume(pem)) != null) { + IRubyObject current = runtime.newString(new ByteList(bytes, false)); + if (block.isGiven()) { + yieldToBlock(ctx, current, pem.getCurrentName(), i, block); + } + i++; + ary.add(current); + pem.continueStream(); + } + + return runtime.newArray(ary); + } + + @JRubyMethod(meta = true) + public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject value, Block block) { + try { + Ruby rt = ctx.getRuntime(); + InputStream in; + if (value.respondsTo("read")) { + in = Streams.tryWrapAsInputStream(rt, value); + } else { + in = new ByteArrayInputStream(toPemIfPossible(value).convertToString().getBytes()); + } + PemInputStream pemin = new PemInputStream(in); + return decodeAry(ctx, pemin, block); + } catch(Exception e) { + throw Errors.newPEMError(ctx.getRuntime(), e.getMessage()); + } + } + + public static IRubyObject toPem(IRubyObject obj) { + return obj.callMethod(obj.getRuntime().getCurrentContext(), "to_pem"); + } + + public static IRubyObject toPemIfPossible(IRubyObject asn1) { + if(asn1.respondsTo("to_pem")) { + return toPem(asn1); + } else { + return asn1; + } + } + + public static void createPem(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mPEM = runtime.defineModuleUnder("PEM", krypt); + mPEM.defineClassUnder("PEMError", kryptError, kryptError.getAllocator()); + mPEM.defineAnnotatedMethods(RubyPem.class); + } + +} diff --git a/src/org/jruby/ext/krypt/asn1/RubyHex.java b/src/org/jruby/ext/krypt/asn1/RubyHex.java new file mode 100644 index 0000000..845d46c --- /dev/null +++ b/src/org/jruby/ext/krypt/asn1/RubyHex.java @@ -0,0 +1,118 @@ +/***** BEGIN LICENSE BLOCK ***** +* Version: CPL 1.0/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Common Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.eclipse.org/legal/cpl-v10.html +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Copyright (C) 2011 +* Hiroshi Nakamura +* Martin Bosslet +* +* Alternatively, the contents of this file may be used under the terms of +* either of the GNU General Public License Version 2 or later (the "GPL"), +* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the CPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the CPL, the GPL or the LGPL. + */ +package org.jruby.ext.krypt.asn1; + +import impl.krypt.asn1.pem.PemInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.Streams; +import org.jruby.runtime.Block; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +/** + * + * @author Martin Bosslet + */ +public class RubyPem { + + private RubyPem() {} + + private static void yieldToBlock(ThreadContext ctx, IRubyObject current, String jname, int ji, Block block) { + IRubyObject name = ctx.getRuntime().newString(jname); + IRubyObject i = RubyNumeric.int2fix(ctx.getRuntime(), ji); + block.yieldSpecific(ctx, current, name, i); + } + + private static IRubyObject decodeAry(ThreadContext ctx, PemInputStream pem, Block block) throws IOException { + Ruby runtime = ctx.getRuntime(); + List ary = new ArrayList(); + byte[] bytes; + int i = 0; + + while ((bytes = Streams.consume(pem)) != null) { + IRubyObject current = runtime.newString(new ByteList(bytes, false)); + if (block.isGiven()) { + yieldToBlock(ctx, current, pem.getCurrentName(), i, block); + } + i++; + ary.add(current); + pem.continueStream(); + } + + return runtime.newArray(ary); + } + + @JRubyMethod(meta = true) + public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject value, Block block) { + try { + Ruby rt = ctx.getRuntime(); + InputStream in; + if (value.respondsTo("read")) { + in = Streams.tryWrapAsInputStream(rt, value); + } else { + in = new ByteArrayInputStream(toPemIfPossible(value).convertToString().getBytes()); + } + PemInputStream pemin = new PemInputStream(in); + return decodeAry(ctx, pemin, block); + } catch(Exception e) { + throw Errors.newPEMError(ctx.getRuntime(), e.getMessage()); + } + } + + public static IRubyObject toPem(IRubyObject obj) { + return obj.callMethod(obj.getRuntime().getCurrentContext(), "to_pem"); + } + + public static IRubyObject toPemIfPossible(IRubyObject asn1) { + if(asn1.respondsTo("to_pem")) { + return toPem(asn1); + } else { + return asn1; + } + } + + public static void createPem(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mPEM = runtime.defineModuleUnder("PEM", krypt); + mPEM.defineClassUnder("PEMError", kryptError, kryptError.getAllocator()); + mPEM.defineAnnotatedMethods(RubyPem.class); + } + +} From dcf7e793c9c8fbd689999c770c8fc042f37c5f71 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 3 Jul 2012 15:42:56 +0530 Subject: [PATCH 05/12] Added Base64 exposing to Ruby World; Need a quick Fix for Cols --- src/org/jruby/ext/krypt/Errors.java | 4 + src/org/jruby/ext/krypt/KryptCoreService.java | 2 + src/org/jruby/ext/krypt/asn1/RubyBase64.java | 118 ------------------ src/org/jruby/ext/krypt/asn1/RubyHex.java | 118 ------------------ src/org/jruby/ext/krypt/codec/RubyBase64.java | 84 +++++++++++++ 5 files changed, 90 insertions(+), 236 deletions(-) delete mode 100644 src/org/jruby/ext/krypt/asn1/RubyBase64.java delete mode 100644 src/org/jruby/ext/krypt/asn1/RubyHex.java create mode 100644 src/org/jruby/ext/krypt/codec/RubyBase64.java diff --git a/src/org/jruby/ext/krypt/Errors.java b/src/org/jruby/ext/krypt/Errors.java index d7ec921..9f14700 100644 --- a/src/org/jruby/ext/krypt/Errors.java +++ b/src/org/jruby/ext/krypt/Errors.java @@ -61,6 +61,10 @@ public static RaiseException newHexError(Ruby rt, String message) { return newError(rt, "Krypt::Hex::HexError", message); } + public static RaiseException newBase64Error(Ruby rt, String message) { + return newError(rt, "Krypt::Base64::Base64Error", message); + } + public static RaiseException newDigestError(Ruby rt, String message) { return newError(rt, "Krypt::Digest::DigestError", message); } diff --git a/src/org/jruby/ext/krypt/KryptCoreService.java b/src/org/jruby/ext/krypt/KryptCoreService.java index de7e7a0..6a4d7b9 100644 --- a/src/org/jruby/ext/krypt/KryptCoreService.java +++ b/src/org/jruby/ext/krypt/KryptCoreService.java @@ -34,6 +34,7 @@ import org.jruby.RubyModule; import org.jruby.ext.krypt.asn1.RubyAsn1; import org.jruby.ext.krypt.asn1.RubyPem; +import org.jruby.ext.krypt.codec.RubyBase64; import org.jruby.ext.krypt.codec.RubyHex; import org.jruby.ext.krypt.digest.RubyDigest; @@ -50,6 +51,7 @@ public static void create(Ruby runtime) { RubyAsn1.createAsn1(runtime, krypt, kryptError); RubyPem.createPem(runtime, krypt, kryptError); RubyHex.createHex(runtime, krypt, kryptError); + RubyBase64.createBase64(runtime, krypt, kryptError); RubyDigest.createDigest(runtime, krypt, kryptError); } } diff --git a/src/org/jruby/ext/krypt/asn1/RubyBase64.java b/src/org/jruby/ext/krypt/asn1/RubyBase64.java deleted file mode 100644 index 845d46c..0000000 --- a/src/org/jruby/ext/krypt/asn1/RubyBase64.java +++ /dev/null @@ -1,118 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** -* Version: CPL 1.0/GPL 2.0/LGPL 2.1 -* -* The contents of this file are subject to the Common Public -* License Version 1.0 (the "License"); you may not use this file -* except in compliance with the License. You may obtain a copy of -* the License at http://www.eclipse.org/legal/cpl-v10.html -* -* Software distributed under the License is distributed on an "AS -* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -* implied. See the License for the specific language governing -* rights and limitations under the License. -* -* Copyright (C) 2011 -* Hiroshi Nakamura -* Martin Bosslet -* -* Alternatively, the contents of this file may be used under the terms of -* either of the GNU General Public License Version 2 or later (the "GPL"), -* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -* in which case the provisions of the GPL or the LGPL are applicable instead -* of those above. If you wish to allow use of your version of this file only -* under the terms of either the GPL or the LGPL, and not to allow others to -* use your version of this file under the terms of the CPL, indicate your -* decision by deleting the provisions above and replace them with the notice -* and other provisions required by the GPL or the LGPL. If you do not delete -* the provisions above, a recipient may use your version of this file under -* the terms of any one of the CPL, the GPL or the LGPL. - */ -package org.jruby.ext.krypt.asn1; - -import impl.krypt.asn1.pem.PemInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.anno.JRubyMethod; -import org.jruby.ext.krypt.Errors; -import org.jruby.ext.krypt.Streams; -import org.jruby.runtime.Block; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * - * @author Martin Bosslet - */ -public class RubyPem { - - private RubyPem() {} - - private static void yieldToBlock(ThreadContext ctx, IRubyObject current, String jname, int ji, Block block) { - IRubyObject name = ctx.getRuntime().newString(jname); - IRubyObject i = RubyNumeric.int2fix(ctx.getRuntime(), ji); - block.yieldSpecific(ctx, current, name, i); - } - - private static IRubyObject decodeAry(ThreadContext ctx, PemInputStream pem, Block block) throws IOException { - Ruby runtime = ctx.getRuntime(); - List ary = new ArrayList(); - byte[] bytes; - int i = 0; - - while ((bytes = Streams.consume(pem)) != null) { - IRubyObject current = runtime.newString(new ByteList(bytes, false)); - if (block.isGiven()) { - yieldToBlock(ctx, current, pem.getCurrentName(), i, block); - } - i++; - ary.add(current); - pem.continueStream(); - } - - return runtime.newArray(ary); - } - - @JRubyMethod(meta = true) - public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject value, Block block) { - try { - Ruby rt = ctx.getRuntime(); - InputStream in; - if (value.respondsTo("read")) { - in = Streams.tryWrapAsInputStream(rt, value); - } else { - in = new ByteArrayInputStream(toPemIfPossible(value).convertToString().getBytes()); - } - PemInputStream pemin = new PemInputStream(in); - return decodeAry(ctx, pemin, block); - } catch(Exception e) { - throw Errors.newPEMError(ctx.getRuntime(), e.getMessage()); - } - } - - public static IRubyObject toPem(IRubyObject obj) { - return obj.callMethod(obj.getRuntime().getCurrentContext(), "to_pem"); - } - - public static IRubyObject toPemIfPossible(IRubyObject asn1) { - if(asn1.respondsTo("to_pem")) { - return toPem(asn1); - } else { - return asn1; - } - } - - public static void createPem(Ruby runtime, RubyModule krypt, RubyClass kryptError) { - RubyModule mPEM = runtime.defineModuleUnder("PEM", krypt); - mPEM.defineClassUnder("PEMError", kryptError, kryptError.getAllocator()); - mPEM.defineAnnotatedMethods(RubyPem.class); - } - -} diff --git a/src/org/jruby/ext/krypt/asn1/RubyHex.java b/src/org/jruby/ext/krypt/asn1/RubyHex.java deleted file mode 100644 index 845d46c..0000000 --- a/src/org/jruby/ext/krypt/asn1/RubyHex.java +++ /dev/null @@ -1,118 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** -* Version: CPL 1.0/GPL 2.0/LGPL 2.1 -* -* The contents of this file are subject to the Common Public -* License Version 1.0 (the "License"); you may not use this file -* except in compliance with the License. You may obtain a copy of -* the License at http://www.eclipse.org/legal/cpl-v10.html -* -* Software distributed under the License is distributed on an "AS -* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -* implied. See the License for the specific language governing -* rights and limitations under the License. -* -* Copyright (C) 2011 -* Hiroshi Nakamura -* Martin Bosslet -* -* Alternatively, the contents of this file may be used under the terms of -* either of the GNU General Public License Version 2 or later (the "GPL"), -* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -* in which case the provisions of the GPL or the LGPL are applicable instead -* of those above. If you wish to allow use of your version of this file only -* under the terms of either the GPL or the LGPL, and not to allow others to -* use your version of this file under the terms of the CPL, indicate your -* decision by deleting the provisions above and replace them with the notice -* and other provisions required by the GPL or the LGPL. If you do not delete -* the provisions above, a recipient may use your version of this file under -* the terms of any one of the CPL, the GPL or the LGPL. - */ -package org.jruby.ext.krypt.asn1; - -import impl.krypt.asn1.pem.PemInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.anno.JRubyMethod; -import org.jruby.ext.krypt.Errors; -import org.jruby.ext.krypt.Streams; -import org.jruby.runtime.Block; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * - * @author Martin Bosslet - */ -public class RubyPem { - - private RubyPem() {} - - private static void yieldToBlock(ThreadContext ctx, IRubyObject current, String jname, int ji, Block block) { - IRubyObject name = ctx.getRuntime().newString(jname); - IRubyObject i = RubyNumeric.int2fix(ctx.getRuntime(), ji); - block.yieldSpecific(ctx, current, name, i); - } - - private static IRubyObject decodeAry(ThreadContext ctx, PemInputStream pem, Block block) throws IOException { - Ruby runtime = ctx.getRuntime(); - List ary = new ArrayList(); - byte[] bytes; - int i = 0; - - while ((bytes = Streams.consume(pem)) != null) { - IRubyObject current = runtime.newString(new ByteList(bytes, false)); - if (block.isGiven()) { - yieldToBlock(ctx, current, pem.getCurrentName(), i, block); - } - i++; - ary.add(current); - pem.continueStream(); - } - - return runtime.newArray(ary); - } - - @JRubyMethod(meta = true) - public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject value, Block block) { - try { - Ruby rt = ctx.getRuntime(); - InputStream in; - if (value.respondsTo("read")) { - in = Streams.tryWrapAsInputStream(rt, value); - } else { - in = new ByteArrayInputStream(toPemIfPossible(value).convertToString().getBytes()); - } - PemInputStream pemin = new PemInputStream(in); - return decodeAry(ctx, pemin, block); - } catch(Exception e) { - throw Errors.newPEMError(ctx.getRuntime(), e.getMessage()); - } - } - - public static IRubyObject toPem(IRubyObject obj) { - return obj.callMethod(obj.getRuntime().getCurrentContext(), "to_pem"); - } - - public static IRubyObject toPemIfPossible(IRubyObject asn1) { - if(asn1.respondsTo("to_pem")) { - return toPem(asn1); - } else { - return asn1; - } - } - - public static void createPem(Ruby runtime, RubyModule krypt, RubyClass kryptError) { - RubyModule mPEM = runtime.defineModuleUnder("PEM", krypt); - mPEM.defineClassUnder("PEMError", kryptError, kryptError.getAllocator()); - mPEM.defineAnnotatedMethods(RubyPem.class); - } - -} diff --git a/src/org/jruby/ext/krypt/codec/RubyBase64.java b/src/org/jruby/ext/krypt/codec/RubyBase64.java new file mode 100644 index 0000000..4d3fc84 --- /dev/null +++ b/src/org/jruby/ext/krypt/codec/RubyBase64.java @@ -0,0 +1,84 @@ +/***** BEGIN LICENSE BLOCK ***** +* Version: CPL 1.0/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Common Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.eclipse.org/legal/cpl-v10.html +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Copyright (C) 2011 +* Hiroshi Nakamura +* Martin Bosslet +* +* Alternatively, the contents of this file may be used under the terms of +* either of the GNU General Public License Version 2 or later (the "GPL"), +* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the CPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the CPL, the GPL or the LGPL. + */ +package org.jruby.ext.krypt.codec; + +import java.io.IOException; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Base64; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +/** + * + * @author Martin Bosslet + */ +public class RubyBase64 { + + private RubyBase64() {} + + @JRubyMethod(meta = true) + public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { + try { + byte[] bytes = data.convertToString().getBytes(); + byte[] encoded = Base64.encode(bytes, 4); + return ctx.getRuntime().newString(new ByteList(encoded, false)); + } catch(IOException ex){ + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + catch (RuntimeException ex) { + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + } + + @JRubyMethod(meta = true) + public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { + try { + byte[] bytes = data.convertToString().getBytes(); + byte[] decoded = Base64.decode(bytes); + return ctx.getRuntime().newString(new ByteList(decoded, false)); + } catch(IOException ex){ + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } catch (RuntimeException ex) { + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + } + + public static void createBase64(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mHex = runtime.defineModuleUnder("Base64", krypt); + mHex.defineClassUnder("Base64Error", kryptError, kryptError.getAllocator()); + mHex.defineAnnotatedMethods(RubyBase64.class); + } + +} \ No newline at end of file From 45d432b72ab7687d0013041dd1aed037dc4a0371 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 3 Jul 2012 17:55:28 +0530 Subject: [PATCH 06/12] Added compliance of cols arguement mirroring c impl --- src/org/jruby/ext/krypt/codec/RubyBase64.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/org/jruby/ext/krypt/codec/RubyBase64.java b/src/org/jruby/ext/krypt/codec/RubyBase64.java index 4d3fc84..c1338f4 100644 --- a/src/org/jruby/ext/krypt/codec/RubyBase64.java +++ b/src/org/jruby/ext/krypt/codec/RubyBase64.java @@ -52,7 +52,7 @@ private RubyBase64() {} public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { try { byte[] bytes = data.convertToString().getBytes(); - byte[] encoded = Base64.encode(bytes, 4); + byte[] encoded = Base64.encode(bytes, -1); return ctx.getRuntime().newString(new ByteList(encoded, false)); } catch(IOException ex){ throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); @@ -62,6 +62,22 @@ public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObjec } } + @JRubyMethod(meta = true) + public static IRubyObject encode(ThreadContext ctx, IRubyObject recv, IRubyObject data, IRubyObject cols) { + try { + int c= (int) cols.convertToInteger().getLongValue(); + byte[] bytes = data.convertToString().getBytes(); + byte[] encoded = Base64.encode(bytes, c); + return ctx.getRuntime().newString(new ByteList(encoded, false)); + } catch(IOException ex){ + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + catch (RuntimeException ex) { + throw Errors.newHexError(ctx.getRuntime(), ex.getMessage()); + } + } + + @JRubyMethod(meta = true) public static IRubyObject decode(ThreadContext ctx, IRubyObject recv, IRubyObject data) { try { From 1798bc88953ea3b06430372c6594a88639861a84 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Thu, 5 Jul 2012 18:58:07 +0530 Subject: [PATCH 07/12] Major update to Cipher, imports and bases most of the implementation form jruby-ossl. This still needs to take into account the proper exposure of Ciphers not available from BC. Also it needs to incorporate the jce, better. --- src/org/jruby/ext/krypt/Errors.java | 4 + src/org/jruby/ext/krypt/KryptCoreService.java | 2 + src/org/jruby/ext/krypt/KryptImpl.java | 95 ++ src/org/jruby/ext/krypt/SimpleSecretKey.java | 57 ++ src/org/jruby/krypt/crypto/Cipher.java | 813 ++++++++++++++++++ 5 files changed, 971 insertions(+) create mode 100644 src/org/jruby/ext/krypt/KryptImpl.java create mode 100644 src/org/jruby/ext/krypt/SimpleSecretKey.java create mode 100644 src/org/jruby/krypt/crypto/Cipher.java diff --git a/src/org/jruby/ext/krypt/Errors.java b/src/org/jruby/ext/krypt/Errors.java index 9f14700..4133e7b 100644 --- a/src/org/jruby/ext/krypt/Errors.java +++ b/src/org/jruby/ext/krypt/Errors.java @@ -69,6 +69,10 @@ public static RaiseException newDigestError(Ruby rt, String message) { return newError(rt, "Krypt::Digest::DigestError", message); } + public static RaiseException newCipherError(Ruby rt, String message) { + return newError(rt, "Krypt::Cipher::CipherError", message); + } + public static RaiseException newError(Ruby rt, String path, String message) { return new RaiseException(rt, getClassFromPath(rt, path), message, true); } diff --git a/src/org/jruby/ext/krypt/KryptCoreService.java b/src/org/jruby/ext/krypt/KryptCoreService.java index 6a4d7b9..4ff7609 100644 --- a/src/org/jruby/ext/krypt/KryptCoreService.java +++ b/src/org/jruby/ext/krypt/KryptCoreService.java @@ -37,6 +37,7 @@ import org.jruby.ext.krypt.codec.RubyBase64; import org.jruby.ext.krypt.codec.RubyHex; import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.ext.openssl.Cipher; /** * @@ -53,5 +54,6 @@ public static void create(Ruby runtime) { RubyHex.createHex(runtime, krypt, kryptError); RubyBase64.createBase64(runtime, krypt, kryptError); RubyDigest.createDigest(runtime, krypt, kryptError); + Cipher.createCipher(runtime, krypt); } } diff --git a/src/org/jruby/ext/krypt/KryptImpl.java b/src/org/jruby/ext/krypt/KryptImpl.java new file mode 100644 index 0000000..1ec1f96 --- /dev/null +++ b/src/org/jruby/ext/krypt/KryptImpl.java @@ -0,0 +1,95 @@ +package org.jruby.ext.krypt; + +import java.security.MessageDigest; + +/** + * + * @author Vipul A M + * + * Credits jruby-ossl + */ + +public class KryptImpl { + + /** + * No instantiating this class... + */ + private KryptImpl() {} + + public static interface KeyAndIv { + byte[] getKey(); + byte[] getIv(); + } + + private static class KeyAndIvImpl implements KeyAndIv { + private final byte[] key; + private final byte[] iv; + public KeyAndIvImpl(byte[] key, byte[] iv) { + this.key = key; + this.iv = iv; + } + public byte[] getKey() { + return key; + } + public byte[] getIv() { + return iv; + } + } + + public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) { + byte[] key = new byte[key_len]; + byte[] iv = new byte[iv_len]; + int key_ix = 0; + int iv_ix = 0; + byte[] md_buf = null; + int nkey = key_len; + int niv = iv_len; + int i = 0; + if(data == null) { + return new KeyAndIvImpl(key,iv); + } + int addmd = 0; + for(;;) { + md.reset(); + if(addmd++ > 0) { + md.update(md_buf); + } + md.update(data); + if(null != salt) { + md.update(salt,0,8); + } + md_buf = md.digest(); + for(i=1;i 0) { + for(;;) { + if(nkey == 0) break; + if(i == md_buf.length) break; + key[key_ix++] = md_buf[i]; + nkey--; + i++; + } + } + if(niv > 0 && i != md_buf.length) { + for(;;) { + if(niv == 0) break; + if(i == md_buf.length) break; + iv[iv_ix++] = md_buf[i]; + niv--; + i++; + } + } + if(nkey == 0 && niv == 0) { + break; + } + } + for(i=0;i + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +/* + * Huge credits to jruby-ossl + */ + +import javax.crypto.SecretKey; + +/** + * @author Ola Bini + */ +public class SimpleSecretKey implements SecretKey { + private static final long serialVersionUID = 1L; + + private final String algorithm; + private final byte[] value; + public SimpleSecretKey(String algorithm, byte[] value) { + this.algorithm = algorithm; + this.value = value; + } + public String getAlgorithm() { + return algorithm; + } + public byte[] getEncoded() { + return value; + } + public String getFormat() { + return "RAW"; + } +}// SimpleSecretKey \ No newline at end of file diff --git a/src/org/jruby/krypt/crypto/Cipher.java b/src/org/jruby/krypt/crypto/Cipher.java new file mode 100644 index 0000000..68933c1 --- /dev/null +++ b/src/org/jruby/krypt/crypto/Cipher.java @@ -0,0 +1,813 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Common Public + * License Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2006, 2007 Ola Bini + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +/* + * Huge Credits to jruby-ossl for this implementatioln + */ + +package org.jruby.krypt.crypto; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; +import org.jruby.*; +import org.jruby.anno.JRubyMethod; +import org.jruby.anno.JRubyModule; +import org.jruby.common.IRubyWarnings; +import org.jruby.common.IRubyWarnings.ID; +import org.jruby.exceptions.RaiseException; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.KryptImpl; +import org.jruby.ext.krypt.SimpleSecretKey; +import org.jruby.ext.krypt.provider.Digest; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; + +/** + * @author Ola Bini + */ +public class Cipher extends RubyObject { + private static final long serialVersionUID = 7727377435222646536L; + + // set to enable debug output + private static final boolean DEBUG = false; + private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() { + + public IRubyObject allocate(Ruby runtime, RubyClass klass) { + return new Cipher(runtime, klass); + } + }; + + public static void createCipher(Ruby runtime, RubyModule mKrypt) { + RubyClass cCipher = mKrypt.defineClassUnder("Cipher", runtime.getObject(), CIPHER_ALLOCATOR); + cCipher.defineAnnotatedMethods(Cipher.class); + cCipher.defineAnnotatedMethods(CipherModule.class); + RubyClass KryptError = mKrypt.getClass("KryptError"); + cCipher.defineClassUnder("CipherError", KryptError, KryptError.getAllocator()); + } + + @JRubyModule(name = "Krypt::Cipher") + public static class CipherModule { + + @JRubyMethod(meta = true) + public static IRubyObject ciphers(IRubyObject recv) { + initializeCiphers(); + List result = new ArrayList(); + for (String cipher : CIPHERS) { + result.add(recv.getRuntime().newString(cipher)); + result.add(recv.getRuntime().newString(cipher.toLowerCase())); + } + return recv.getRuntime().newArray(result); + } + + public static boolean isSupportedCipher(String name) { + initializeCiphers(); + return CIPHERS.indexOf(name.toUpperCase()) != -1; + } + private static boolean initialized = false; + private static final List CIPHERS = new ArrayList(); + + private static void initializeCiphers() { + synchronized (CIPHERS) { + if (initialized) { + return; + } + String[] other = {"AES128", "AES192", "AES256", "BLOWFISH", "RC2-40-CBC", "RC2-64-CBC", "RC4", "RC4-40", "CAST", "CAST-CBC"}; + String[] bases = {"AES-128", "AES-192", "AES-256", "BF", "DES", "DES-EDE", "DES-EDE3", "RC2", "CAST5"}; + String[] suffixes = {"", "-CBC", "-CFB", "-CFB1", "-CFB8", "-ECB", "-OFB"}; + for (int i = 0, j = bases.length; i < j; i++) { + for (int k = 0, l = suffixes.length; k < l; k++) { + String val = bases[i] + suffixes[k]; + if (tryCipher(val)) { + CIPHERS.add(val.toUpperCase()); + } + } + } + for (int i = 0, j = other.length; i < j; i++) { + if (tryCipher(other[i])) { + CIPHERS.add(other[i].toUpperCase()); + } + } + initialized = true; + } + } + } + + public static class Algorithm { + + private static final Set BLOCK_MODES; + + static { + BLOCK_MODES = new HashSet(); + + BLOCK_MODES.add("CBC"); + BLOCK_MODES.add("CFB"); + BLOCK_MODES.add("CFB1"); + BLOCK_MODES.add("CFB8"); + BLOCK_MODES.add("ECB"); + BLOCK_MODES.add("OFB"); + } + + public static String jsseToOssl(String inName, int keyLen) { + String cryptoBase = null; + String cryptoVersion = null; + String cryptoMode = null; + String[] parts = inName.split("/"); + if (parts.length != 1 && parts.length != 3) { + return null; + } + cryptoBase = parts[0]; + if (parts.length > 2) { + cryptoMode = parts[1]; + // padding: parts[2] is not used + } + if (!BLOCK_MODES.contains(cryptoMode)) { + cryptoVersion = cryptoMode; + cryptoMode = "CBC"; + } + if (cryptoMode == null) { + cryptoMode = "CBC"; + } + if (cryptoBase.equals("DESede")) { + cryptoBase = "DES"; + cryptoVersion = "EDE3"; + } else if (cryptoBase.equals("Blowfish")) { + cryptoBase = "BF"; + } + if (cryptoVersion == null) { + cryptoVersion = String.valueOf(keyLen); + } + return cryptoBase + "-" + cryptoVersion + "-" + cryptoMode; + } + + public static String[] osslToJsse(String inName) { + // assume PKCS5Padding + return osslToJsse(inName, null); + } + + public static String[] osslToJsse(String inName, String padding) { + String[] split = inName.split("-"); + String cryptoBase = split[0]; + String cryptoVersion = null; + String cryptoMode = null; + String realName = null; + + String paddingType; + if (padding == null || padding.equalsIgnoreCase("PKCS5Padding")) { + paddingType = "PKCS5Padding"; + } else if (padding.equals("0") || padding.equalsIgnoreCase("NoPadding")) { + paddingType = "NoPadding"; + } else if (padding.equalsIgnoreCase("ISO10126Padding")) { + paddingType = "ISO10126Padding"; + } else { + paddingType = "PKCS5Padding"; + } + + if ("bf".equalsIgnoreCase(cryptoBase)) { + cryptoBase = "Blowfish"; + } + + if (split.length == 3) { + cryptoVersion = split[1]; + cryptoMode = split[2]; + } else if (split.length == 2) { + cryptoMode = split[1]; + } else { + cryptoMode = "CBC"; + } + + if (cryptoBase.equalsIgnoreCase("CAST")) { + realName = "CAST5"; + } else if (cryptoBase.equalsIgnoreCase("DES") && "EDE3".equalsIgnoreCase(cryptoVersion)) { + realName = "DESede"; + } else { + realName = cryptoBase; + } + + if (!BLOCK_MODES.contains(cryptoMode.toUpperCase())) { + cryptoVersion = cryptoMode; + cryptoMode = "CBC"; + } else if (cryptoMode.equalsIgnoreCase("CFB1")) { + // uglish SunJCE cryptoMode normalization. + cryptoMode = "CFB"; + } + + if (realName.equalsIgnoreCase("RC4")) { + realName = "RC4"; + cryptoMode = "NONE"; + paddingType = "NoPadding"; + } else { + realName = realName + "/" + cryptoMode + "/" + paddingType; + } + + return new String[]{cryptoBase, cryptoVersion, cryptoMode, realName, paddingType}; + } + + public static int[] osslKeyIvLength(String name) { + String[] values = Algorithm.osslToJsse(name); + String cryptoBase = values[0]; + String cryptoVersion = values[1]; + String cryptoMode = values[2]; + String realName = values[3]; + + int keyLen = -1; + int ivLen = -1; + + if (hasLen(cryptoBase) && null != cryptoVersion) { + try { + keyLen = Integer.parseInt(cryptoVersion) / 8; + } catch (NumberFormatException e) { + keyLen = -1; + } + } + if (keyLen == -1) { + if ("DES".equalsIgnoreCase(cryptoBase)) { + ivLen = 8; + if ("EDE3".equalsIgnoreCase(cryptoVersion)) { + keyLen = 24; + } else { + keyLen = 8; + } + } else if ("RC4".equalsIgnoreCase(cryptoBase)) { + ivLen = 0; + keyLen = 16; + } else { + keyLen = 16; + try { + if ((javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8) < keyLen) { + keyLen = javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8; + } + } catch (Exception e) { + // I hate checked exceptions + } + } + } + + if (ivLen == -1) { + if ("AES".equalsIgnoreCase(cryptoBase)) { + ivLen = 16; + } else { + ivLen = 8; + } + } + return new int[] { keyLen, ivLen }; + } + + public static boolean hasLen(String cryptoBase) { + return "AES".equalsIgnoreCase(cryptoBase) || "RC2".equalsIgnoreCase(cryptoBase) || "RC4".equalsIgnoreCase(cryptoBase); + } + } + + private static boolean tryCipher(final String rubyName) { + String cryptoMode = Algorithm.osslToJsse(rubyName, null)[3]; + try { + javax.crypto.Cipher.getInstance(cryptoMode); + return true; + } catch (NoSuchAlgorithmException nsae) { + //Removed BC Dependency + //TODO: Fix with actual impl + //try { + // OpenSSLReal.getCipherBC(cryptoMode); + // return true; + //} catch (GeneralSecurityException gse) { + // return false; + //} + return false; + } catch (Exception e) { + return false; + } + } + + public Cipher(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + private javax.crypto.Cipher ciph; + private String name; + private String cryptoBase; + private String cryptoVersion; + private String cryptoMode; + private String padding_type; + private String realName; + private int keyLen = -1; + private int generateKeyLen = -1; + private int ivLen = -1; + private boolean encryptMode = true; + //private IRubyObject[] modeParams; + private boolean ciphInited = false; + private byte[] key; + private byte[] realIV; + private byte[] orgIV; + private String padding; + + void dumpVars() { + System.out.println("***** Cipher instance vars ****"); + System.out.println("name = " + name); + System.out.println("cryptoBase = " + cryptoBase); + System.out.println("cryptoVersion = " + cryptoVersion); + System.out.println("cryptoMode = " + cryptoMode); + System.out.println("padding_type = " + padding_type); + System.out.println("realName = " + realName); + System.out.println("keyLen = " + keyLen); + System.out.println("ivLen = " + ivLen); + System.out.println("ciph block size = " + ciph.getBlockSize()); + System.out.println("encryptMode = " + encryptMode); + System.out.println("ciphInited = " + ciphInited); + System.out.println("key.length = " + (key == null ? 0 : key.length)); + System.out.println("iv.length = " + (this.realIV == null ? 0 : this.realIV.length)); + System.out.println("padding = " + padding); + System.out.println("ciphAlgo = " + ciph.getAlgorithm()); + System.out.println("*******************************"); + } + + @JRubyMethod(required = 1) + public IRubyObject initialize(IRubyObject str) { + name = str.toString(); + if (!CipherModule.isSupportedCipher(name)) { + throw newCipherError(getRuntime(), String.format("unsupported cipher algorithm (%s)", name)); + } + if (ciph != null) { + throw getRuntime().newRuntimeError("Cipher already inititalized!"); + } + updateCipher(name, padding); + return this; + } + + @Override + @JRubyMethod(required = 1) + public IRubyObject initialize_copy(IRubyObject obj) { + if (this == obj) { + return this; + } + + checkFrozen(); + + cryptoBase = ((Cipher) obj).cryptoBase; + cryptoVersion = ((Cipher) obj).cryptoVersion; + cryptoMode = ((Cipher) obj).cryptoMode; + padding_type = ((Cipher) obj).padding_type; + realName = ((Cipher) obj).realName; + name = ((Cipher) obj).name; + keyLen = ((Cipher) obj).keyLen; + ivLen = ((Cipher) obj).ivLen; + encryptMode = ((Cipher) obj).encryptMode; + ciphInited = false; + if (((Cipher) obj).key != null) { + key = new byte[((Cipher) obj).key.length]; + System.arraycopy(((Cipher) obj).key, 0, key, 0, key.length); + } else { + key = null; + } + if (((Cipher) obj).realIV != null) { + this.realIV = new byte[((Cipher) obj).realIV.length]; + System.arraycopy(((Cipher) obj).realIV, 0, this.realIV, 0, this.realIV.length); + } else { + this.realIV = null; + } + this.orgIV = this.realIV; + padding = ((Cipher) obj).padding; + + ciph = getCipher(); + + return this; + } + + @JRubyMethod + public IRubyObject name() { + return getRuntime().newString(name); + } + + @JRubyMethod + public IRubyObject key_len() { + return getRuntime().newFixnum(keyLen); + } + + @JRubyMethod + public IRubyObject iv_len() { + return getRuntime().newFixnum(ivLen); + } + + @JRubyMethod(name = "key_len=", required = 1) + public IRubyObject set_key_len(IRubyObject len) { + this.keyLen = RubyNumeric.fix2int(len); + return len; + } + + @JRubyMethod(name = "key=", required = 1) + public IRubyObject set_key(IRubyObject key) { + byte[] keyBytes; + try { + keyBytes = key.convertToString().getBytes(); + } catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + } + throw newCipherError(getRuntime(), e.getMessage()); + } + if (keyBytes.length < keyLen) { + throw newCipherError(getRuntime(), "key length to short"); + } + + if (keyBytes.length > keyLen) { + byte[] keys = new byte[keyLen]; + System.arraycopy(keyBytes, 0, keys, 0, keyLen); + keyBytes = keys; + } + + this.key = keyBytes; + return key; + } + + @JRubyMethod(name = "iv=", required = 1) + public IRubyObject set_iv(IRubyObject iv) { + byte[] ivBytes; + try { + ivBytes = iv.convertToString().getBytes(); + } catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + } + throw newCipherError(getRuntime(), e.getMessage()); + } + if (ivBytes.length < ivLen) { + throw newCipherError(getRuntime(), "iv length to short"); + } else { + // EVP_CipherInit_ex uses leading IV length of given sequence. + byte[] iv2 = new byte[ivLen]; + System.arraycopy(ivBytes, 0, iv2, 0, ivLen); + this.realIV = iv2; + } + this.orgIV = this.realIV; + if (!isStreamCipher()) { + ciphInited = false; + } + return iv; + } + + @JRubyMethod + public IRubyObject block_size() { + checkInitialized(); + if (isStreamCipher()) { + // getBlockSize() returns 0 for stream cipher in JCE. OpenSSL returns 1 for RC4. + return getRuntime().newFixnum(1); + } + return getRuntime().newFixnum(ciph.getBlockSize()); + } + + protected void init(IRubyObject[] args, boolean encrypt) { + org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); + + encryptMode = encrypt; + ciphInited = false; + + if (args.length > 0) { + /* + * oops. this code mistakes salt for IV. + * We deprecated the arguments for this method, but we decided + * keeping this behaviour for backward compatibility. + */ + byte[] pass = args[0].convertToString().getBytes(); + byte[] iv = null; + try { + iv = "OpenSSL for Ruby rulez!".getBytes("ISO8859-1"); + byte[] iv2 = new byte[this.ivLen]; + System.arraycopy(iv, 0, iv2, 0, this.ivLen); + iv = iv2; + } catch (Exception e) { + } + + if (args.length > 1 && !args[1].isNil()) { + getRuntime().getWarnings().warning(ID.MISCELLANEOUS, "key derivation by " + getMetaClass().getRealClass().getName() + "#encrypt is deprecated; use " + getMetaClass().getRealClass().getName() + "::pkcs5_keyivgen instead"); + iv = args[1].convertToString().getBytes(); + if (iv.length > this.ivLen) { + byte[] iv2 = new byte[this.ivLen]; + System.arraycopy(iv, 0, iv2, 0, this.ivLen); + iv = iv2; + } + } + + MessageDigest digest=null; + try { + digest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException ex) { + Errors.newDigestError(getRuntime(), "cannot get digest instance"); + } + KryptImpl.KeyAndIv result = KryptImpl.EVP_BytesToKey(keyLen, ivLen, digest, iv, pass, 2048); + this.key = result.getKey(); + this.realIV = iv; + this.orgIV = this.realIV; + } + } + + @JRubyMethod(optional = 2) + public IRubyObject encrypt(IRubyObject[] args) { + this.realIV = orgIV; + init(args, true); + return this; + } + + @JRubyMethod(optional = 2) + public IRubyObject decrypt(IRubyObject[] args) { + this.realIV = orgIV; + init(args, false); + return this; + } + + @JRubyMethod + public IRubyObject reset() { + checkInitialized(); + if (!isStreamCipher()) { + this.realIV = orgIV; + doInitialize(); + } + return this; + } + + private void updateCipher(String name, String padding) { + // given 'rc4' must be 'RC4' here. OpenSSL checks it as a LN of object + // ID and set SN. We don't check 'name' is allowed as a LN in ASN.1 for + // the possibility of JCE specific algorithm so just do upperCase here + // for OpenSSL compatibility. + this.name = name.toUpperCase(); + this.padding = padding; + + String[] values = Algorithm.osslToJsse(name, padding); + cryptoBase = values[0]; + cryptoVersion = values[1]; + cryptoMode = values[2]; + realName = values[3]; + padding_type = values[4]; + + int[] lengths = Algorithm.osslKeyIvLength(name); + keyLen = lengths[0]; + ivLen = lengths[1]; + if ("DES".equalsIgnoreCase(cryptoBase)) { + generateKeyLen = keyLen / 8 * 7; + } + + ciph = getCipher(); + } + + javax.crypto.Cipher getCipher() { + try { + return javax.crypto.Cipher.getInstance(realName); + } catch (NoSuchAlgorithmException e) { + //Removes BC Dependency + //TODO: Fix independent impl + //try { + // return OpenSSLReal.getCipherBC(realName); + //} catch (GeneralSecurityException ignore) { + + //} + throw newCipherError(getRuntime(), "unsupported cipher algorithm (" + realName + ")"); + } catch (javax.crypto.NoSuchPaddingException e) { + throw newCipherError(getRuntime(), "unsupported cipher padding (" + realName + ")"); + } + } + + @JRubyMethod(required = 1, optional = 3) + public IRubyObject pkcs5_keyivgen(IRubyObject[] args) throws NoSuchAlgorithmException { + org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 4); + byte[] pass = args[0].convertToString().getBytes(); + byte[] salt = null; + int iter = 2048; + IRubyObject vdigest = getRuntime().getNil(); + if (args.length > 1) { + if (!args[1].isNil()) { + salt = args[1].convertToString().getBytes(); + } + if (args.length > 2) { + if (!args[2].isNil()) { + iter = RubyNumeric.fix2int(args[2]); + } + if (args.length > 3) { + vdigest = args[3]; + } + } + } + if (null != salt) { + if (salt.length != 8) { + throw newCipherError(getRuntime(), "salt must be an 8-octet string"); + } + } + + final String algorithm = vdigest.isNil() ? "MD5" : ((Digest) vdigest).getName(); + //TODO: Create a KeyAndIV Impl + MessageDigest digest = MessageDigest.getInstance(algorithm);//Digest.getDigest(algorithm, getRuntime()); + KryptImpl.KeyAndIv result = KryptImpl.EVP_BytesToKey(keyLen, ivLen, digest, salt, pass, iter); + this.key = result.getKey(); + this.realIV = result.getIv(); + this.orgIV = this.realIV; + + doInitialize(); + + return getRuntime().getNil(); + } + + private void doInitialize() { + if (DEBUG) { + System.out.println("*** doInitialize"); + dumpVars(); + } + checkInitialized(); + if (key == null) { + throw newCipherError(getRuntime(), "key not specified"); + } + try { + if (!"ECB".equalsIgnoreCase(cryptoMode)) { + if (this.realIV == null) { + this.realIV = new byte[ivLen]; + System.arraycopy("OpenSSL for JRuby rulez".getBytes(), 0, + this.realIV, 0, ivLen); + } + if ("RC2".equalsIgnoreCase(cryptoBase)) { + this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey("RC2", this.key), new RC2ParameterSpec(this.key.length * 8, this.realIV)); + } else if ("RC4".equalsIgnoreCase(cryptoBase)) { + this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey("RC4", this.key)); + } else { + this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(realName.split("/")[0], this.key), new IvParameterSpec(this.realIV)); + } + } else { + this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(realName.split("/")[0], this.key)); + } + } catch (java.security.InvalidKeyException ike) { + throw Errors.newCipherError(getRuntime(), ike.getMessage() + ": possibly you need to install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for your JRE"); + } + catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + } + throw newCipherError(getRuntime(), e.getMessage()); + } + ciphInited = true; + } + private byte[] lastIv = null; + + @JRubyMethod + public IRubyObject update(IRubyObject data) { + if (DEBUG) { + System.out.println("*** update [" + data + "]"); + } + checkInitialized(); + byte[] val = data.convertToString().getBytes(); + if (val.length == 0) { + throw getRuntime().newArgumentError("data must not be empty"); + } + + if (!ciphInited) { + if (DEBUG) { + System.out.println("BEFORE INITING"); + } + doInitialize(); + if (DEBUG) { + System.out.println("AFTER INITING"); + } + } + + byte[] str = new byte[0]; + try { + byte[] out = ciph.update(val); + if (out != null) { + str = out; + + if (this.realIV != null) { + if (lastIv == null) { + lastIv = new byte[ivLen]; + } + byte[] tmpIv = encryptMode ? out : val; + if (tmpIv.length >= ivLen) { + System.arraycopy(tmpIv, tmpIv.length - ivLen, lastIv, 0, ivLen); + } + } + } + } catch (Exception e) { + if (DEBUG) { + e.printStackTrace(); + } + throw newCipherError(getRuntime(), e.getMessage()); + } + + return getRuntime().newString(new ByteList(str, false)); + } + + @JRubyMethod(name = "<<") + public IRubyObject update_deprecated(IRubyObject data) { + getRuntime().getWarnings().warn(IRubyWarnings.ID.DEPRECATED_METHOD, "" + this.getMetaClass().getRealClass().getName() + "#<< is deprecated; use " + this.getMetaClass().getRealClass().getName() + "#update instead"); + return update(data); + } + + @JRubyMethod(name = "final") + public IRubyObject _final() { + checkInitialized(); + if (!ciphInited) { + doInitialize(); + } + // trying to allow update after final like cruby-openssl. Bad idea. + if ("RC4".equalsIgnoreCase(cryptoBase)) { + return getRuntime().newString(""); + } + ByteList str = new ByteList(ByteList.NULL_ARRAY); + try { + byte[] out = ciph.doFinal(); + if (out != null) { + str = new ByteList(out, false); + // TODO: Modifying this line appears to fix the issue, but I do + // not have a good reason for why. Best I can tell, lastIv needs + // to be set regardless of encryptMode, so we'll go with this + // for now. JRUBY-3335. + //if(this.realIV != null && encryptMode) { + if (this.realIV != null) { + if (lastIv == null) { + lastIv = new byte[ivLen]; + } + byte[] tmpIv = out; + if (tmpIv.length >= ivLen) { + System.arraycopy(tmpIv, tmpIv.length - ivLen, lastIv, 0, ivLen); + } + } + } + if (this.realIV != null) { + this.realIV = lastIv; + doInitialize(); + } + } catch (Exception e) { + throw newCipherError(getRuntime(), e.getMessage()); + } + return getRuntime().newString(str); + } + + @JRubyMethod(name = "padding=") + public IRubyObject set_padding(IRubyObject padding) { + updateCipher(name, padding.toString()); + return padding; + } + + String getAlgorithm() { + return this.ciph.getAlgorithm(); + } + + String getName() { + return this.name; + } + + String getCryptoBase() { + return this.cryptoBase; + } + + String getCryptoMode() { + return this.cryptoMode; + } + + int getKeyLen() { + return keyLen; + } + + int getGenerateKeyLen() { + return (generateKeyLen == -1) ? keyLen : generateKeyLen; + } + + private void checkInitialized() { + if (ciph == null) { + throw getRuntime().newRuntimeError("Cipher not inititalized!"); + } + } + + private boolean isStreamCipher() { + return ciph.getBlockSize() == 0; + } + + private static RaiseException newCipherError(Ruby runtime, String message) { + return Errors.newError(runtime, "Krypt::Cipher::CipherError", message); + } +} \ No newline at end of file From e8e1e90a2350aa1e31dcc686a2df7e2d5d089fc9 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 13 Aug 2012 13:37:36 +0530 Subject: [PATCH 08/12] Fixed Cipher import --- src/org/jruby/ext/krypt/KryptCoreService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jruby/ext/krypt/KryptCoreService.java b/src/org/jruby/ext/krypt/KryptCoreService.java index 4ff7609..5c5770a 100644 --- a/src/org/jruby/ext/krypt/KryptCoreService.java +++ b/src/org/jruby/ext/krypt/KryptCoreService.java @@ -37,7 +37,7 @@ import org.jruby.ext.krypt.codec.RubyBase64; import org.jruby.ext.krypt.codec.RubyHex; import org.jruby.ext.krypt.digest.RubyDigest; -import org.jruby.ext.openssl.Cipher; +import org.jruby.krypt.crypto.Cipher; /** * From e37f457af87077d0b50de63559c53542fecbb4e4 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Thu, 16 Aug 2012 00:20:31 +0530 Subject: [PATCH 09/12] Introduce Digital Signatures with DSA/RSA support. --- src/org/jruby/ext/krypt/Errors.java | 4 + src/org/jruby/ext/krypt/KryptCoreService.java | 2 + .../jruby/ext/krypt/digest/RubyDigest.java | 4 + .../jruby/ext/krypt/signature/RubyDSA.java | 143 ++++++++++++++++++ .../jruby/ext/krypt/signature/RubyRSA.java | 142 +++++++++++++++++ .../ext/krypt/signature/RubySignature.java | 25 +++ 6 files changed, 320 insertions(+) create mode 100644 src/org/jruby/ext/krypt/signature/RubyDSA.java create mode 100644 src/org/jruby/ext/krypt/signature/RubyRSA.java create mode 100644 src/org/jruby/ext/krypt/signature/RubySignature.java diff --git a/src/org/jruby/ext/krypt/Errors.java b/src/org/jruby/ext/krypt/Errors.java index 4133e7b..b3c956e 100644 --- a/src/org/jruby/ext/krypt/Errors.java +++ b/src/org/jruby/ext/krypt/Errors.java @@ -73,6 +73,10 @@ public static RaiseException newCipherError(Ruby rt, String message) { return newError(rt, "Krypt::Cipher::CipherError", message); } + public static RaiseException newSignatureError(Ruby rt, String message) { + return newError(rt, "Krypt::SignatureError::DSAError", message); + } + public static RaiseException newError(Ruby rt, String path, String message) { return new RaiseException(rt, getClassFromPath(rt, path), message, true); } diff --git a/src/org/jruby/ext/krypt/KryptCoreService.java b/src/org/jruby/ext/krypt/KryptCoreService.java index 5c5770a..f96554d 100644 --- a/src/org/jruby/ext/krypt/KryptCoreService.java +++ b/src/org/jruby/ext/krypt/KryptCoreService.java @@ -37,6 +37,7 @@ import org.jruby.ext.krypt.codec.RubyBase64; import org.jruby.ext.krypt.codec.RubyHex; import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.ext.krypt.signature.RubySignature; import org.jruby.krypt.crypto.Cipher; /** @@ -55,5 +56,6 @@ public static void create(Ruby runtime) { RubyBase64.createBase64(runtime, krypt, kryptError); RubyDigest.createDigest(runtime, krypt, kryptError); Cipher.createCipher(runtime, krypt); + RubySignature.createSignature(runtime, krypt, kryptError ); } } diff --git a/src/org/jruby/ext/krypt/digest/RubyDigest.java b/src/org/jruby/ext/krypt/digest/RubyDigest.java index 4eb0101..ee57d19 100644 --- a/src/org/jruby/ext/krypt/digest/RubyDigest.java +++ b/src/org/jruby/ext/krypt/digest/RubyDigest.java @@ -126,6 +126,10 @@ public IRubyObject name(ThreadContext ctx) { return ctx.getRuntime().newString(this.digest.getName()); } + public String getName(){ + return digest.getName(); + } + @JRubyMethod public IRubyObject digest_length(ThreadContext ctx) { return RubyNumeric.int2fix(ctx.getRuntime(), this.digest.getDigestLength()); diff --git a/src/org/jruby/ext/krypt/signature/RubyDSA.java b/src/org/jruby/ext/krypt/signature/RubyDSA.java new file mode 100644 index 0000000..c2d344a --- /dev/null +++ b/src/org/jruby/ext/krypt/signature/RubyDSA.java @@ -0,0 +1,143 @@ + +package org.jruby.ext.krypt.signature; + +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyDSA extends RubyObject{ + + private Signature sig; + private KeyPair pair; + private String name=""; + + private static ObjectAllocator ALLOCATOR = new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass type) { + return new RubyDSA(runtime, type); + } + }; + + protected RubyDSA(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createDSA(Ruby runtime, RubyModule mSig, RubyClass sigError) { + + RubyClass cDSA = mSig.defineClassUnder("DSA", null, ALLOCATOR );; + RubyClass dsaErr=mSig.defineClassUnder("DSAError", sigError, sigError.getAllocator()); + cDSA.defineAnnotatedMethods(RubyDSA.class); + } + + + @JRubyMethod + public RubyString getName(ThreadContext ctx) { + return RubyString.newString(ctx.getRuntime(), sig.getAlgorithm()); + } + + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject rbDigest) throws NoSuchAlgorithmException, InvalidKeyException { + Ruby runtime = ctx.getRuntime(); + if (!(rbDigest instanceof RubyDigest)) getRuntime().newArgumentError(" digest object expected"); + RubyDigest dig = (RubyDigest) rbDigest; + String digName=dig.getName(); + + /* + * STUB!!! + * Generate a key pair + * This need to be modularized to RubyKey Internally + * and Amends for Keystore + */ + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + keyGen.initialize(1024, random); + pair = keyGen.generateKeyPair(); + + PublicKey pub=pair.getPublic(); + PrivateKey priv= pair.getPrivate(); + name=digName+"withDSA"; + sig = Signature.getInstance(name); + sig.initSign(priv); + + return this; + } + + @JRubyMethod + public IRubyObject update(ThreadContext ctx, IRubyObject rbytes){ + try { + sig.update(rbytes.asJavaString().getBytes()); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + @JRubyMethod + public IRubyObject sign(ThreadContext ctx){ + try { + sig.sign(); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + public void checkVerify(Ruby rt){ + try { + sig.initVerify(pair.getPublic()); + } catch (InvalidKeyException ex) { + Errors.newSignatureError(rt, " could not initialize verification"); + } + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes){ + checkVerify(ctx.getRuntime()); + try { + return ((sig.verify(sbytes.asJavaString().getBytes())) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes, IRubyObject off, IRubyObject len ){ + int offset = RubyNumeric.num2int(off); + int length= RubyNumeric.num2int(len); + try { + return ((sig.verify(sbytes.asJavaString().getBytes(), offset, length)) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + +} diff --git a/src/org/jruby/ext/krypt/signature/RubyRSA.java b/src/org/jruby/ext/krypt/signature/RubyRSA.java new file mode 100644 index 0000000..7e06788 --- /dev/null +++ b/src/org/jruby/ext/krypt/signature/RubyRSA.java @@ -0,0 +1,142 @@ + +package org.jruby.ext.krypt.signature; + +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyRSA extends RubyObject{ + + private Signature sig; + private KeyPair pair; + private String name=""; + + private static ObjectAllocator ALLOCATOR = new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass type) { + return new RubyDSA(runtime, type); + } + }; + + protected RubyRSA(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createRSA(Ruby runtime, RubyModule mSig, RubyClass sigError) { + RubyClass cRSA = mSig.defineClassUnder("RSA", null, ALLOCATOR );; + RubyClass rsaErr=mSig.defineClassUnder("RSAError", sigError, sigError.getAllocator()); + cRSA.defineAnnotatedMethods(RubyRSA.class); + } + + + @JRubyMethod + public RubyString getName(ThreadContext ctx) { + return RubyString.newString(ctx.getRuntime(), sig.getAlgorithm()); + } + + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject rbDigest) throws NoSuchAlgorithmException, InvalidKeyException { + Ruby runtime = ctx.getRuntime(); + if (!(rbDigest instanceof RubyDigest)) getRuntime().newArgumentError(" digest object expected"); + RubyDigest dig = (RubyDigest) rbDigest; + String digName=dig.getName(); + + /* + * STUB!!! + * Generate a key pair + * This need to be modularized to RubyKey Internally + * and Amends for Keystore + */ + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + keyGen.initialize(1024, random); + pair = keyGen.generateKeyPair(); + + PublicKey pub=pair.getPublic(); + PrivateKey priv= pair.getPrivate(); + name=digName+"withRSA"; + sig = Signature.getInstance(name); + sig.initSign(priv); + + return this; + } + + @JRubyMethod + public IRubyObject update(ThreadContext ctx, IRubyObject rbytes){ + try { + sig.update(rbytes.asJavaString().getBytes()); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + @JRubyMethod + public IRubyObject sign(ThreadContext ctx){ + try { + sig.sign(); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + public void checkVerify(Ruby rt){ + try { + sig.initVerify(pair.getPublic()); + } catch (InvalidKeyException ex) { + Errors.newSignatureError(rt, " could not initialize verification"); + } + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes){ + checkVerify(ctx.getRuntime()); + try { + return ((sig.verify(sbytes.asJavaString().getBytes())) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes, IRubyObject off, IRubyObject len ){ + int offset = RubyNumeric.num2int(off); + int length= RubyNumeric.num2int(len); + try { + return ((sig.verify(sbytes.asJavaString().getBytes(), offset, length)) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + +} diff --git a/src/org/jruby/ext/krypt/signature/RubySignature.java b/src/org/jruby/ext/krypt/signature/RubySignature.java new file mode 100644 index 0000000..33be193 --- /dev/null +++ b/src/org/jruby/ext/krypt/signature/RubySignature.java @@ -0,0 +1,25 @@ + +package org.jruby.ext.krypt.signature; + +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; + +/** + * + * @author Vipul A M + */ +public class RubySignature extends RubyObject { + + protected RubySignature(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createSignature(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mSig = runtime.getOrCreateModule("Signature"); + RubyClass sigErr=mSig.defineClassUnder("SignatureError", kryptError, kryptError.getAllocator()); + RubyDSA.createDSA(runtime, mSig, sigErr); + RubyRSA.createRSA(runtime, mSig, sigErr); + } +} From 0235c3b0637dd5b3c8e9ad910a96139c10aaaa6e Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 20 Aug 2012 20:09:01 +0530 Subject: [PATCH 10/12] Introduce RubyKey for Public/Private Key management for RSA/DSA --- src/org/jruby/ext/krypt/Errors.java | 4 ++ .../ext/krypt/key/RubyDSAPrivateKey.java | 65 ++++++++++++++++++ .../jruby/ext/krypt/key/RubyDSAPublicKey.java | 65 ++++++++++++++++++ src/org/jruby/ext/krypt/key/RubyKey.java | 27 ++++++++ .../ext/krypt/key/RubyRSAPrivateKey.java | 66 +++++++++++++++++++ .../jruby/ext/krypt/key/RubyRSAPublicKey.java | 65 ++++++++++++++++++ .../jruby/ext/krypt/signature/RubyDSA.java | 63 +++++++++--------- .../jruby/ext/krypt/signature/RubyRSA.java | 62 ++++++++--------- .../ext/krypt/signature/RubySignature.java | 2 +- 9 files changed, 356 insertions(+), 63 deletions(-) create mode 100644 src/org/jruby/ext/krypt/key/RubyDSAPrivateKey.java create mode 100644 src/org/jruby/ext/krypt/key/RubyDSAPublicKey.java create mode 100644 src/org/jruby/ext/krypt/key/RubyKey.java create mode 100644 src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java create mode 100644 src/org/jruby/ext/krypt/key/RubyRSAPublicKey.java diff --git a/src/org/jruby/ext/krypt/Errors.java b/src/org/jruby/ext/krypt/Errors.java index b3c956e..21f44e9 100644 --- a/src/org/jruby/ext/krypt/Errors.java +++ b/src/org/jruby/ext/krypt/Errors.java @@ -77,6 +77,10 @@ public static RaiseException newSignatureError(Ruby rt, String message) { return newError(rt, "Krypt::SignatureError::DSAError", message); } + public static RaiseException newKeyError(Ruby rt, String message) { + return newError(rt, "Krypt::Key::KeyError", message); + } + public static RaiseException newError(Ruby rt, String path, String message) { return new RaiseException(rt, getClassFromPath(rt, path), message, true); } diff --git a/src/org/jruby/ext/krypt/key/RubyDSAPrivateKey.java b/src/org/jruby/ext/krypt/key/RubyDSAPrivateKey.java new file mode 100644 index 0000000..d9191c9 --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyDSAPrivateKey.java @@ -0,0 +1,65 @@ +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.DSAPrivateKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyDSAPrivateKey extends RubyObject { + + private DSAPrivateKey pkey; + + protected RubyDSAPrivateKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPrivKey = mKey.defineModuleUnder("DSAPrivateKey"); + mPrivKey.defineAnnotatedMethods(RubyDSAPrivateKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPrivateKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPrivateKeyFromBytes(byte[] privateKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("DSA"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject); + pkey= (DSAPrivateKey) fac.generatePrivate(privKeySpec); + } + + public DSAPrivateKey getKey(){ + return pkey; + } + +} diff --git a/src/org/jruby/ext/krypt/key/RubyDSAPublicKey.java b/src/org/jruby/ext/krypt/key/RubyDSAPublicKey.java new file mode 100644 index 0000000..9da1d76 --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyDSAPublicKey.java @@ -0,0 +1,65 @@ + +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyDSAPublicKey extends RubyObject { + + private DSAPublicKey pkey; + + protected RubyDSAPublicKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPubKey = mKey.defineModuleUnder("DSAPublicKey"); + mPubKey.defineAnnotatedMethods(RubyDSAPublicKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPublicKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPublicKeyFromBytes(byte[] pubKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("DSA"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(pubKeyObject); + pkey= (DSAPublicKey) fac.generatePublic(pubKeySpec); + } + + public DSAPublicKey getKey(){ + return pkey; + } +} diff --git a/src/org/jruby/ext/krypt/key/RubyKey.java b/src/org/jruby/ext/krypt/key/RubyKey.java new file mode 100644 index 0000000..b5838ca --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyKey.java @@ -0,0 +1,27 @@ + +package org.jruby.ext.krypt.key; + +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyKey extends RubyObject { + + protected RubyKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule krypt, RubyClass kryptError) { + RubyModule mKey = krypt.defineModuleUnder("Key"); + RubyClass keyErr=mKey.defineClassUnder("KeyError", kryptError, kryptError.getAllocator()); + RubyDSAPrivateKey.createKey(runtime, mKey, keyErr); + RubyDSAPublicKey.createKey(runtime, mKey, keyErr); + RubyRSAPrivateKey.createKey(runtime, mKey, keyErr); + RubyRSAPublicKey.createKey(runtime, mKey, keyErr); + } +} diff --git a/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java b/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java new file mode 100644 index 0000000..1cb357a --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java @@ -0,0 +1,66 @@ +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyRSAPrivateKey extends RubyObject { + + private RSAPrivateKey pkey; + + protected RubyRSAPrivateKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPrivKey = mKey.defineModuleUnder("RSAPrivateKey"); + mPrivKey.defineAnnotatedMethods(RubyRSAPrivateKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPrivateKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPrivateKeyFromBytes(byte[] privateKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject); + pkey= (RSAPrivateKey) fac.generatePrivate(privKeySpec); + } + + public RSAPrivateKey getKey(){ + return pkey; + } + +} diff --git a/src/org/jruby/ext/krypt/key/RubyRSAPublicKey.java b/src/org/jruby/ext/krypt/key/RubyRSAPublicKey.java new file mode 100644 index 0000000..2bf83b7 --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyRSAPublicKey.java @@ -0,0 +1,65 @@ + +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyRSAPublicKey extends RubyObject { + + private RSAPublicKey pkey; + + protected RubyRSAPublicKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPubKey = mKey.defineModuleUnder("RSAPublicKey"); + mPubKey.defineAnnotatedMethods(RubyRSAPublicKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPublicKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPublicKeyFromBytes(byte[] pubKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(pubKeyObject); + pkey= (RSAPublicKey) fac.generatePublic(pubKeySpec); + } + + public RSAPublicKey getKey(){ + return pkey; + } +} diff --git a/src/org/jruby/ext/krypt/signature/RubyDSA.java b/src/org/jruby/ext/krypt/signature/RubyDSA.java index c2d344a..37459fe 100644 --- a/src/org/jruby/ext/krypt/signature/RubyDSA.java +++ b/src/org/jruby/ext/krypt/signature/RubyDSA.java @@ -2,14 +2,15 @@ package org.jruby.ext.krypt.signature; import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; +import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import org.jruby.Ruby; import org.jruby.RubyBoolean; import org.jruby.RubyClass; @@ -20,6 +21,8 @@ import org.jruby.anno.JRubyMethod; import org.jruby.ext.krypt.Errors; import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.ext.krypt.key.RubyDSAPrivateKey; +import org.jruby.ext.krypt.key.RubyDSAPublicKey; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; @@ -31,7 +34,6 @@ public class RubyDSA extends RubyObject{ private Signature sig; - private KeyPair pair; private String name=""; private static ObjectAllocator ALLOCATOR = new ObjectAllocator() { @@ -54,7 +56,7 @@ public static void createDSA(Ruby runtime, RubyModule mSig, RubyClass sigError) @JRubyMethod - public RubyString getName(ThreadContext ctx) { + public RubyString name(ThreadContext ctx) { return RubyString.newString(ctx.getRuntime(), sig.getAlgorithm()); } @@ -65,25 +67,8 @@ public IRubyObject initialize(ThreadContext ctx, IRubyObject rbDigest) throws No if (!(rbDigest instanceof RubyDigest)) getRuntime().newArgumentError(" digest object expected"); RubyDigest dig = (RubyDigest) rbDigest; String digName=dig.getName(); - - /* - * STUB!!! - * Generate a key pair - * This need to be modularized to RubyKey Internally - * and Amends for Keystore - */ - - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); - SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); - keyGen.initialize(1024, random); - pair = keyGen.generateKeyPair(); - - PublicKey pub=pair.getPublic(); - PrivateKey priv= pair.getPrivate(); name=digName+"withDSA"; sig = Signature.getInstance(name); - sig.initSign(priv); - return this; } @@ -106,18 +91,34 @@ public IRubyObject sign(ThreadContext ctx){ } return this; } + - public void checkVerify(Ruby rt){ - try { - sig.initVerify(pair.getPublic()); - } catch (InvalidKeyException ex) { - Errors.newSignatureError(rt, " could not initialize verification"); - } + @JRubyMethod + public IRubyObject initv(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyDSAPublicKey){ + sig.initVerify(((RubyDSAPublicKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("DSA"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initVerify(fac.generatePublic(pubKeySpec)); + } + return this; + } + + @JRubyMethod + public IRubyObject inits(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyDSAPrivateKey){ + sig.initSign(((RubyDSAPrivateKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("DSA"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initSign(fac.generatePrivate(privKeySpec)); + } + return this; } @JRubyMethod public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes){ - checkVerify(ctx.getRuntime()); try { return ((sig.verify(sbytes.asJavaString().getBytes())) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; } catch (SignatureException ex) { diff --git a/src/org/jruby/ext/krypt/signature/RubyRSA.java b/src/org/jruby/ext/krypt/signature/RubyRSA.java index 7e06788..16b81ec 100644 --- a/src/org/jruby/ext/krypt/signature/RubyRSA.java +++ b/src/org/jruby/ext/krypt/signature/RubyRSA.java @@ -2,14 +2,13 @@ package org.jruby.ext.krypt.signature; import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; +import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import org.jruby.Ruby; import org.jruby.RubyBoolean; import org.jruby.RubyClass; @@ -20,6 +19,8 @@ import org.jruby.anno.JRubyMethod; import org.jruby.ext.krypt.Errors; import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.ext.krypt.key.RubyRSAPrivateKey; +import org.jruby.ext.krypt.key.RubyRSAPublicKey; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; @@ -31,7 +32,6 @@ public class RubyRSA extends RubyObject{ private Signature sig; - private KeyPair pair; private String name=""; private static ObjectAllocator ALLOCATOR = new ObjectAllocator() { @@ -46,6 +46,7 @@ protected RubyRSA(Ruby runtime, RubyClass type) { } public static void createRSA(Ruby runtime, RubyModule mSig, RubyClass sigError) { + RubyClass cRSA = mSig.defineClassUnder("RSA", null, ALLOCATOR );; RubyClass rsaErr=mSig.defineClassUnder("RSAError", sigError, sigError.getAllocator()); cRSA.defineAnnotatedMethods(RubyRSA.class); @@ -53,7 +54,7 @@ public static void createRSA(Ruby runtime, RubyModule mSig, RubyClass sigError) @JRubyMethod - public RubyString getName(ThreadContext ctx) { + public RubyString name(ThreadContext ctx) { return RubyString.newString(ctx.getRuntime(), sig.getAlgorithm()); } @@ -64,25 +65,8 @@ public IRubyObject initialize(ThreadContext ctx, IRubyObject rbDigest) throws No if (!(rbDigest instanceof RubyDigest)) getRuntime().newArgumentError(" digest object expected"); RubyDigest dig = (RubyDigest) rbDigest; String digName=dig.getName(); - - /* - * STUB!!! - * Generate a key pair - * This need to be modularized to RubyKey Internally - * and Amends for Keystore - */ - - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); - SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); - keyGen.initialize(1024, random); - pair = keyGen.generateKeyPair(); - - PublicKey pub=pair.getPublic(); - PrivateKey priv= pair.getPrivate(); name=digName+"withRSA"; sig = Signature.getInstance(name); - sig.initSign(priv); - return this; } @@ -105,18 +89,34 @@ public IRubyObject sign(ThreadContext ctx){ } return this; } + - public void checkVerify(Ruby rt){ - try { - sig.initVerify(pair.getPublic()); - } catch (InvalidKeyException ex) { - Errors.newSignatureError(rt, " could not initialize verification"); - } + @JRubyMethod + public IRubyObject initv(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyRSAPublicKey){ + sig.initVerify(((RubyRSAPublicKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initVerify(fac.generatePublic(pubKeySpec)); + } + return this; + } + + @JRubyMethod + public IRubyObject inits(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyRSAPrivateKey){ + sig.initSign(((RubyRSAPrivateKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initSign(fac.generatePrivate(privKeySpec)); + } + return this; } @JRubyMethod public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes){ - checkVerify(ctx.getRuntime()); try { return ((sig.verify(sbytes.asJavaString().getBytes())) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; } catch (SignatureException ex) { diff --git a/src/org/jruby/ext/krypt/signature/RubySignature.java b/src/org/jruby/ext/krypt/signature/RubySignature.java index 33be193..0d3329c 100644 --- a/src/org/jruby/ext/krypt/signature/RubySignature.java +++ b/src/org/jruby/ext/krypt/signature/RubySignature.java @@ -17,7 +17,7 @@ protected RubySignature(Ruby runtime, RubyClass type) { } public static void createSignature(Ruby runtime, RubyModule krypt, RubyClass kryptError) { - RubyModule mSig = runtime.getOrCreateModule("Signature"); + RubyModule mSig = krypt.defineModuleUnder("Signature"); RubyClass sigErr=mSig.defineClassUnder("SignatureError", kryptError, kryptError.getAllocator()); RubyDSA.createDSA(runtime, mSig, sigErr); RubyRSA.createRSA(runtime, mSig, sigErr); From 1fb9d17ec647bb79625fec49989b61c1e67bb53f Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 20 Aug 2012 20:09:48 +0530 Subject: [PATCH 11/12] Remove Ununsed imports --- src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java | 1 - src/org/jruby/ext/krypt/signature/RubyDSA.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java b/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java index 1cb357a..16fe1c2 100644 --- a/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java +++ b/src/org/jruby/ext/krypt/key/RubyRSAPrivateKey.java @@ -2,7 +2,6 @@ import java.security.GeneralSecurityException; import java.security.KeyFactory; -import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateKey; import java.security.spec.EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec; diff --git a/src/org/jruby/ext/krypt/signature/RubyDSA.java b/src/org/jruby/ext/krypt/signature/RubyDSA.java index 37459fe..fb6e370 100644 --- a/src/org/jruby/ext/krypt/signature/RubyDSA.java +++ b/src/org/jruby/ext/krypt/signature/RubyDSA.java @@ -6,8 +6,6 @@ import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; import java.security.spec.EncodedKeySpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; From 1a2f4191f3965731bb962c0e671473c4d9b0b2d7 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 20 Aug 2012 20:49:52 +0530 Subject: [PATCH 12/12] Introduce EC Signature/Key --- .../jruby/ext/krypt/key/RubyECPrivateKey.java | 66 +++++++++ .../jruby/ext/krypt/key/RubyECPublicKey.java | 67 +++++++++ src/org/jruby/ext/krypt/key/RubyKey.java | 2 + src/org/jruby/ext/krypt/signature/RubyEC.java | 140 ++++++++++++++++++ .../ext/krypt/signature/RubySignature.java | 1 + 5 files changed, 276 insertions(+) create mode 100644 src/org/jruby/ext/krypt/key/RubyECPrivateKey.java create mode 100644 src/org/jruby/ext/krypt/key/RubyECPublicKey.java create mode 100644 src/org/jruby/ext/krypt/signature/RubyEC.java diff --git a/src/org/jruby/ext/krypt/key/RubyECPrivateKey.java b/src/org/jruby/ext/krypt/key/RubyECPrivateKey.java new file mode 100644 index 0000000..19e2c9d --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyECPrivateKey.java @@ -0,0 +1,66 @@ +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyECPrivateKey extends RubyObject { + + private ECPrivateKey pkey; + + protected RubyECPrivateKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPrivKey = mKey.defineModuleUnder("ECPrivateKey"); + mPrivKey.defineAnnotatedMethods(RubyECPrivateKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPrivateKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPrivateKeyFromBytes(byte[] privateKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("EC"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject); + pkey= (ECPrivateKey) fac.generatePrivate(privKeySpec); + } + + public ECPrivateKey getKey(){ + return pkey; + } + +} diff --git a/src/org/jruby/ext/krypt/key/RubyECPublicKey.java b/src/org/jruby/ext/krypt/key/RubyECPublicKey.java new file mode 100644 index 0000000..1c60817 --- /dev/null +++ b/src/org/jruby/ext/krypt/key/RubyECPublicKey.java @@ -0,0 +1,67 @@ +package org.jruby.ext.krypt.key; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyECPublicKey extends RubyObject { + + private ECPublicKey pkey; + + protected RubyECPublicKey(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createKey(Ruby runtime, RubyModule mKey, RubyClass keyError) { + RubyModule mPrivKey = mKey.defineModuleUnder("ECPublicKey"); + mPrivKey.defineAnnotatedMethods(RubyECPublicKey.class); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject keyData) { + try { + getPublicKeyFromBytes(keyData.asJavaString().getBytes()); + } catch (GeneralSecurityException ex) { + Errors.newKeyError(ctx.getRuntime()," unable to create key from given data"); + } + return this; + } + + @JRubyMethod + public IRubyObject encoded(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getEncoded()); + } + + @JRubyMethod + public IRubyObject algorithm(ThreadContext ctx, IRubyObject keyData) { + return RubyString.newString(ctx.getRuntime(), pkey.getAlgorithm()); + } + + private void getPublicKeyFromBytes(byte[] pubKeyObject) throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("EC"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(pubKeyObject); + pkey= (ECPublicKey) fac.generatePublic(pubKeySpec); + } + + public ECPublicKey getKey(){ + return pkey; + } + +} diff --git a/src/org/jruby/ext/krypt/key/RubyKey.java b/src/org/jruby/ext/krypt/key/RubyKey.java index b5838ca..b7c2334 100644 --- a/src/org/jruby/ext/krypt/key/RubyKey.java +++ b/src/org/jruby/ext/krypt/key/RubyKey.java @@ -23,5 +23,7 @@ public static void createKey(Ruby runtime, RubyModule krypt, RubyClass kryptErro RubyDSAPublicKey.createKey(runtime, mKey, keyErr); RubyRSAPrivateKey.createKey(runtime, mKey, keyErr); RubyRSAPublicKey.createKey(runtime, mKey, keyErr); + RubyECPrivateKey.createKey(runtime, mKey, keyErr); + RubyECPublicKey.createKey(runtime, mKey, keyErr); } } diff --git a/src/org/jruby/ext/krypt/signature/RubyEC.java b/src/org/jruby/ext/krypt/signature/RubyEC.java new file mode 100644 index 0000000..96956e0 --- /dev/null +++ b/src/org/jruby/ext/krypt/signature/RubyEC.java @@ -0,0 +1,140 @@ + +package org.jruby.ext.krypt.signature; + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyMethod; +import org.jruby.ext.krypt.Errors; +import org.jruby.ext.krypt.digest.RubyDigest; +import org.jruby.ext.krypt.key.RubyECPrivateKey; +import org.jruby.ext.krypt.key.RubyECPublicKey; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * + * @author Vipul A M + */ +public class RubyEC extends RubyObject{ + + private Signature sig; + private String name=""; + + private static ObjectAllocator ALLOCATOR = new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass type) { + return new RubyEC(runtime, type); + } + }; + + protected RubyEC(Ruby runtime, RubyClass type) { + super(runtime, type); + } + + public static void createEC(Ruby runtime, RubyModule mSig, RubyClass sigError) { + RubyClass cEC = mSig.defineClassUnder("EC", null, ALLOCATOR );; + RubyClass ecErr=mSig.defineClassUnder("ECError", sigError, sigError.getAllocator()); + cEC.defineAnnotatedMethods(RubyEC.class); + } + + + @JRubyMethod + public RubyString name(ThreadContext ctx) { + return RubyString.newString(ctx.getRuntime(), sig.getAlgorithm()); + } + + + @JRubyMethod + public IRubyObject initialize(ThreadContext ctx, IRubyObject rbDigest) throws NoSuchAlgorithmException, InvalidKeyException { + if (!(rbDigest instanceof RubyDigest)) getRuntime().newArgumentError(" digest object expected"); + RubyDigest dig = (RubyDigest) rbDigest; + String digName=dig.getName(); + name=digName+"withECDSA"; + sig = Signature.getInstance(name); + return this; + } + + @JRubyMethod + public IRubyObject update(ThreadContext ctx, IRubyObject rbytes){ + try { + sig.update(rbytes.asJavaString().getBytes()); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + @JRubyMethod + public IRubyObject sign(ThreadContext ctx){ + try { + sig.sign(); + } catch (SignatureException ex) { + getRuntime().newArgumentError(" invalid bytes provided for update"); + } + return this; + } + + + @JRubyMethod + public IRubyObject initv(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyECPublicKey){ + sig.initVerify(((RubyECPublicKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("EC"); + EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initVerify(fac.generatePublic(pubKeySpec)); + } + return this; + } + + @JRubyMethod + public IRubyObject inits(ThreadContext ctx, IRubyObject key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{ + if(key instanceof RubyECPrivateKey){ + sig.initSign(((RubyECPrivateKey)key).getKey()); + } else{ + KeyFactory fac = KeyFactory.getInstance("EC"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(key.asJavaString().getBytes()); + sig.initSign(fac.generatePrivate(privKeySpec)); + } + return this; + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes){ + try { + return ((sig.verify(sbytes.asJavaString().getBytes())) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + + @JRubyMethod + public RubyBoolean verify(ThreadContext ctx, IRubyObject sbytes, IRubyObject off, IRubyObject len ){ + int offset = RubyNumeric.num2int(off); + int length= RubyNumeric.num2int(len); + try { + return ((sig.verify(sbytes.asJavaString().getBytes(), offset, length)) ? RubyBoolean.newBoolean(ctx.getRuntime(), true) : RubyBoolean.newBoolean(ctx.getRuntime(), false)) ; + } catch (SignatureException ex) { + Errors.newSignatureError(ctx.getRuntime()," could not verify"); + } finally{ + return RubyBoolean.newBoolean(ctx.getRuntime(), false); + } + } + +} diff --git a/src/org/jruby/ext/krypt/signature/RubySignature.java b/src/org/jruby/ext/krypt/signature/RubySignature.java index 0d3329c..31c7865 100644 --- a/src/org/jruby/ext/krypt/signature/RubySignature.java +++ b/src/org/jruby/ext/krypt/signature/RubySignature.java @@ -21,5 +21,6 @@ public static void createSignature(Ruby runtime, RubyModule krypt, RubyClass kry RubyClass sigErr=mSig.defineClassUnder("SignatureError", kryptError, kryptError.getAllocator()); RubyDSA.createDSA(runtime, mSig, sigErr); RubyRSA.createRSA(runtime, mSig, sigErr); + RubyEC.createEC(runtime, mSig, sigErr); } }