ed25519 1.2.4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +5 -0
  4. data/.rubocop.yml +35 -0
  5. data/.travis.yml +26 -0
  6. data/CHANGES.md +70 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +12 -0
  9. data/LICENSE +22 -0
  10. data/README.md +170 -0
  11. data/Rakefile +27 -0
  12. data/appveyor.yml +21 -0
  13. data/ed25519.gemspec +32 -0
  14. data/ed25519.png +0 -0
  15. data/ext/ed25519_jruby/LICENSE.txt +123 -0
  16. data/ext/ed25519_jruby/README.md +77 -0
  17. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAEngine.java +491 -0
  18. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAKey.java +31 -0
  19. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPrivateKey.java +338 -0
  20. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSAPublicKey.java +275 -0
  21. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/EdDSASecurityProvider.java +59 -0
  22. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyFactory.java +75 -0
  23. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/KeyPairGenerator.java +97 -0
  24. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/Utils.java +103 -0
  25. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Constants.java +23 -0
  26. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Curve.java +100 -0
  27. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Encoding.java +54 -0
  28. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/Field.java +99 -0
  29. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/FieldElement.java +76 -0
  30. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/GroupElement.java +1034 -0
  31. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ScalarOps.java +34 -0
  32. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerFieldElement.java +131 -0
  33. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerLittleEndianEncoding.java +102 -0
  34. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/BigIntegerScalarOps.java +37 -0
  35. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/bigint/package.html +6 -0
  36. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519FieldElement.java +988 -0
  37. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519LittleEndianEncoding.java +256 -0
  38. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/math/ed25519/Ed25519ScalarOps.java +693 -0
  39. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAGenParameterSpec.java +32 -0
  40. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveSpec.java +35 -0
  41. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSANamedCurveTable.java +71 -0
  42. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java +97 -0
  43. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java +133 -0
  44. data/ext/ed25519_jruby/net/i2p/crypto/eddsa/spec/EdDSAPublicKeySpec.java +61 -0
  45. data/ext/ed25519_jruby/org/cryptorb/Ed25519Provider.java +95 -0
  46. data/ext/ed25519_ref10/api.h +4 -0
  47. data/ext/ed25519_ref10/base.h +1344 -0
  48. data/ext/ed25519_ref10/base2.h +40 -0
  49. data/ext/ed25519_ref10/d.h +1 -0
  50. data/ext/ed25519_ref10/d2.h +1 -0
  51. data/ext/ed25519_ref10/ed25519_ref10.c +99 -0
  52. data/ext/ed25519_ref10/ed25519_ref10.h +33 -0
  53. data/ext/ed25519_ref10/extconf.rb +9 -0
  54. data/ext/ed25519_ref10/fe.c +1085 -0
  55. data/ext/ed25519_ref10/fe.h +56 -0
  56. data/ext/ed25519_ref10/ge.c +407 -0
  57. data/ext/ed25519_ref10/ge.h +95 -0
  58. data/ext/ed25519_ref10/ge_add.h +97 -0
  59. data/ext/ed25519_ref10/ge_madd.h +88 -0
  60. data/ext/ed25519_ref10/ge_msub.h +88 -0
  61. data/ext/ed25519_ref10/ge_p2_dbl.h +73 -0
  62. data/ext/ed25519_ref10/ge_sub.h +97 -0
  63. data/ext/ed25519_ref10/keypair.c +22 -0
  64. data/ext/ed25519_ref10/open.c +47 -0
  65. data/ext/ed25519_ref10/pow22523.h +160 -0
  66. data/ext/ed25519_ref10/pow225521.h +160 -0
  67. data/ext/ed25519_ref10/sc.h +17 -0
  68. data/ext/ed25519_ref10/sc_muladd.c +366 -0
  69. data/ext/ed25519_ref10/sc_reduce.c +272 -0
  70. data/ext/ed25519_ref10/sha512.c +304 -0
  71. data/ext/ed25519_ref10/sha512.h +8 -0
  72. data/ext/ed25519_ref10/sign.c +41 -0
  73. data/ext/ed25519_ref10/sqrtm1.h +1 -0
  74. data/ext/ed25519_ref10/verify.c +40 -0
  75. data/lib/ed25519.rb +72 -0
  76. data/lib/ed25519/signing_key.rb +60 -0
  77. data/lib/ed25519/verify_key.rb +44 -0
  78. data/lib/ed25519/version.rb +5 -0
  79. metadata +137 -0
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/clean"
6
+ CLEAN.include("**/*.o", "**/*.so", "**/*.bundle", "*.jar", "pkg", "tmp")
7
+
8
+ if defined? JRUBY_VERSION
9
+ require "rake/javaextensiontask"
10
+ Rake::JavaExtensionTask.new("ed25519_jruby") do |ext|
11
+ ext.ext_dir = "ext/ed25519_jruby"
12
+ end
13
+ else
14
+ require "rake/extensiontask"
15
+
16
+ Rake::ExtensionTask.new("ed25519_ref10") do |ext|
17
+ ext.ext_dir = "ext/ed25519_ref10"
18
+ end
19
+ end
20
+
21
+ require "rspec/core/rake_task"
22
+ RSpec::Core::RakeTask.new
23
+
24
+ require "rubocop/rake_task"
25
+ RuboCop::RakeTask.new
26
+
27
+ task default: %w[compile spec rubocop]
@@ -0,0 +1,21 @@
1
+ branches:
2
+ only:
3
+ - master
4
+
5
+ environment:
6
+ PATH: C:\Ruby%RUBY_VERSION%\DevKit\mingw\bin;C:\Ruby%RUBY_VERSION%\bin;C:\Ruby%RUBY_VERSION%\DevKit\bin;%PATH%
7
+ matrix:
8
+ - RUBY_VERSION: "21-x64"
9
+ - RUBY_VERSION: "22-x64"
10
+ - RUBY_VERSION: "23-x64"
11
+ - RUBY_VERSION: "24-x64"
12
+
13
+ build: off
14
+
15
+ test_script:
16
+ - SET RAKEOPT=-rdevkit
17
+ - ruby -v
18
+ - gem -v
19
+ - bundle -v
20
+ - bundle
21
+ - bundle exec rake compile spec
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("lib/ed25519/version", __dir__)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ed25519"
7
+ spec.version = Ed25519::VERSION
8
+ spec.authors = ["Tony Arcieri"]
9
+ spec.email = ["tony.arcieri@gmail.com"]
10
+ spec.summary = "An efficient digital signature library providing the Ed25519 algorithm"
11
+ spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
12
+ A Ruby binding to the Ed25519 elliptic curve public-key signature system
13
+ described in RFC 8032.
14
+ DESCRIPTION
15
+ spec.homepage = "https://github.com/crypto-rb/ed25519"
16
+ spec.license = "MIT"
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ if defined? JRUBY_VERSION
23
+ spec.platform = "java"
24
+ spec.files << "lib/ed25519_jruby.jar"
25
+ else
26
+ spec.platform = Gem::Platform::RUBY
27
+ spec.extensions = ["ext/ed25519_ref10/extconf.rb"]
28
+ end
29
+
30
+ spec.required_ruby_version = ">= 2.0.0"
31
+ spec.add_development_dependency "bundler", "~> 1.16"
32
+ end
Binary file
@@ -0,0 +1,123 @@
1
+ Creative Commons Legal Code
2
+
3
+ CC0 1.0 Universal
4
+
5
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12
+ HEREUNDER.
13
+
14
+ Statement of Purpose
15
+
16
+ The laws of most jurisdictions throughout the world automatically confer
17
+ exclusive Copyright and Related Rights (defined below) upon the creator
18
+ and subsequent owner(s) (each and all, an "owner") of an original work of
19
+ authorship and/or a database (each, a "Work").
20
+
21
+ Certain owners wish to permanently relinquish those rights to a Work for
22
+ the purpose of contributing to a commons of creative, cultural and
23
+ scientific works ("Commons") that the public can reliably and without fear
24
+ of later claims of infringement build upon, modify, incorporate in other
25
+ works, reuse and redistribute as freely as possible in any form whatsoever
26
+ and for any purposes, including without limitation commercial purposes.
27
+ These owners may contribute to the Commons to promote the ideal of a free
28
+ culture and the further production of creative, cultural and scientific
29
+ works, or to gain reputation or greater distribution for their Work in
30
+ part through the use and efforts of others.
31
+
32
+ For these and/or other purposes and motivations, and without any
33
+ expectation of additional consideration or compensation, the person
34
+ associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35
+ is an owner of Copyright and Related Rights in the Work, voluntarily
36
+ elects to apply CC0 to the Work and publicly distribute the Work under its
37
+ terms, with knowledge of his or her Copyright and Related Rights in the
38
+ Work and the meaning and intended legal effect of CC0 on those rights.
39
+
40
+ 1. Copyright and Related Rights. A Work made available under CC0 may be
41
+ protected by copyright and related or neighboring rights ("Copyright and
42
+ Related Rights"). Copyright and Related Rights include, but are not
43
+ limited to, the following:
44
+
45
+ i. the right to reproduce, adapt, distribute, perform, display,
46
+ communicate, and translate a Work;
47
+ ii. moral rights retained by the original author(s) and/or performer(s);
48
+ iii. publicity and privacy rights pertaining to a person's image or
49
+ likeness depicted in a Work;
50
+ iv. rights protecting against unfair competition in regards to a Work,
51
+ subject to the limitations in paragraph 4(a), below;
52
+ v. rights protecting the extraction, dissemination, use and reuse of data
53
+ in a Work;
54
+ vi. database rights (such as those arising under Directive 96/9/EC of the
55
+ European Parliament and of the Council of 11 March 1996 on the legal
56
+ protection of databases, and under any national implementation
57
+ thereof, including any amended or successor version of such
58
+ directive); and
59
+ vii. other similar, equivalent or corresponding rights throughout the
60
+ world based on applicable law or treaty, and any national
61
+ implementations thereof.
62
+
63
+ 2. Waiver. To the greatest extent permitted by, but not in contravention
64
+ of, applicable law, Affirmer hereby overtly, fully, permanently,
65
+ irrevocably and unconditionally waives, abandons, and surrenders all of
66
+ Affirmer's Copyright and Related Rights and associated claims and causes
67
+ of action, whether now known or unknown (including existing as well as
68
+ future claims and causes of action), in the Work (i) in all territories
69
+ worldwide, (ii) for the maximum duration provided by applicable law or
70
+ treaty (including future time extensions), (iii) in any current or future
71
+ medium and for any number of copies, and (iv) for any purpose whatsoever,
72
+ including without limitation commercial, advertising or promotional
73
+ purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74
+ member of the public at large and to the detriment of Affirmer's heirs and
75
+ successors, fully intending that such Waiver shall not be subject to
76
+ revocation, rescission, cancellation, termination, or any other legal or
77
+ equitable action to disrupt the quiet enjoyment of the Work by the public
78
+ as contemplated by Affirmer's express Statement of Purpose.
79
+
80
+ 3. Public License Fallback. Should any part of the Waiver for any reason
81
+ be judged legally invalid or ineffective under applicable law, then the
82
+ Waiver shall be preserved to the maximum extent permitted taking into
83
+ account Affirmer's express Statement of Purpose. In addition, to the
84
+ extent the Waiver is so judged Affirmer hereby grants to each affected
85
+ person a royalty-free, non transferable, non sublicensable, non exclusive,
86
+ irrevocable and unconditional license to exercise Affirmer's Copyright and
87
+ Related Rights in the Work (i) in all territories worldwide, (ii) for the
88
+ maximum duration provided by applicable law or treaty (including future
89
+ time extensions), (iii) in any current or future medium and for any number
90
+ of copies, and (iv) for any purpose whatsoever, including without
91
+ limitation commercial, advertising or promotional purposes (the
92
+ "License"). The License shall be deemed effective as of the date CC0 was
93
+ applied by Affirmer to the Work. Should any part of the License for any
94
+ reason be judged legally invalid or ineffective under applicable law, such
95
+ partial invalidity or ineffectiveness shall not invalidate the remainder
96
+ of the License, and in such case Affirmer hereby affirms that he or she
97
+ will not (i) exercise any of his or her remaining Copyright and Related
98
+ Rights in the Work or (ii) assert any associated claims and causes of
99
+ action with respect to the Work, in either case contrary to Affirmer's
100
+ express Statement of Purpose.
101
+
102
+ 4. Limitations and Disclaimers.
103
+
104
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
105
+ surrendered, licensed or otherwise affected by this document.
106
+ b. Affirmer offers the Work as-is and makes no representations or
107
+ warranties of any kind concerning the Work, express, implied,
108
+ statutory or otherwise, including without limitation warranties of
109
+ title, merchantability, fitness for a particular purpose, non
110
+ infringement, or the absence of latent or other defects, accuracy, or
111
+ the present or absence of errors, whether or not discoverable, all to
112
+ the greatest extent permissible under applicable law.
113
+ c. Affirmer disclaims responsibility for clearing rights of other persons
114
+ that may apply to the Work or any use thereof, including without
115
+ limitation any person's Copyright and Related Rights in the Work.
116
+ Further, Affirmer disclaims responsibility for obtaining any necessary
117
+ consents, permissions or other rights required for any use of the
118
+ Work.
119
+ d. Affirmer understands and acknowledges that Creative Commons is not a
120
+ party to this document and has no duty or obligation with respect to
121
+ this CC0 or use of the Work.
122
+
123
+ For more information, please see https://creativecommons.org/publicdomain/zero/1.0/
@@ -0,0 +1,77 @@
1
+ EdDSA-Java
2
+ ==========
3
+
4
+ [![Build Status](https://travis-ci.org/str4d/ed25519-java.svg?branch=master)](https://travis-ci.org/str4d/ed25519-java)
5
+
6
+ This is an implementation of EdDSA in Java. Structurally, it is based on the ref10 implementation in SUPERCOP (see https://ed25519.cr.yp.to/software.html).
7
+
8
+ There are two internal implementations:
9
+ * A port of the radix-2^51 operations in ref10 - fast and constant-time, but only useful for Ed25519.
10
+ * A generic version using BigIntegers for calculation - a bit slower and not constant-time, but compatible with any EdDSA parameter specification.
11
+
12
+
13
+ To use
14
+ ------
15
+
16
+ Download the latest .jar from the releases tab and place it in your classpath.
17
+
18
+ Gradle users:
19
+
20
+ ```
21
+ compile 'net.i2p.crypto:eddsa:0.2.0'
22
+ ```
23
+
24
+ The code requires Java 6 (for e.g. the `Arrays.copyOfRange()` calls in `EdDSAEngine.engineVerify()`).
25
+
26
+ The JUnit4 tests require the Hamcrest library `hamcrest-all.jar`.
27
+
28
+ This code is released to the public domain and can be used for any purpose. See `LICENSE.txt` for details.
29
+
30
+ Disclaimer
31
+ ----------
32
+
33
+ There are **no** guarantees that this is secure for all cases, and users should
34
+ review the code themselves before depending on it. PRs that fix bugs or improve
35
+ reviewability are very welcome. Additionally:
36
+
37
+ - The unit test suite includes tests against
38
+ [the data from the original Python implementation](https://ed25519.cr.yp.to/python/sign.input).
39
+ - The code (as of 97cea3f0d910fc627c7b57b1bc4d783cdd0c2a4a) was reviewed by
40
+ [an independent developer](https://github.com/BloodyRookie).
41
+ - The code (as of dc9f58f2c874463c15465326efc040d17a627b3a) was audited by an independent third party,
42
+ and the one issue found [was fixed](https://github.com/str4d/ed25519-java/pull/31).
43
+
44
+ Code comparison
45
+ ---------------
46
+
47
+ For ease of following, here are the main methods in ref10 and their equivalents in this codebase:
48
+
49
+ | EdDSA Operation | ref10 function | Java function |
50
+ | --------------- | -------------- | ------------- |
51
+ | Generate keypair | `crypto_sign_keypair` | `EdDSAPrivateKeySpec` constructor |
52
+ | Sign message | `crypto_sign` | `EdDSAEngine.engineSign` |
53
+ | Verify signature | `crypto_sign_open` | `EdDSAEngine.engineVerify` |
54
+
55
+ | EdDSA point arithmetic | ref10 function | Java function |
56
+ | ---------------------- | -------------- | ------------- |
57
+ | `R = b * B` | `ge_scalarmult_base` | `GroupElement.scalarMultiply` |
58
+ | `R = a*A + b*B` | `ge_double_scalarmult_vartime` | `GroupElement.doubleScalarMultiplyVariableTime` |
59
+ | `R = 2 * P` | `ge_p2_dbl` | `GroupElement.dbl` |
60
+ | `R = P + Q` | `ge_madd`, `ge_add` | `GroupElement.madd`, `GroupElement.add` |
61
+ | `R = P - Q` | `ge_msub`, `ge_sub` | `GroupElement.msub`, `GroupElement.sub` |
62
+
63
+
64
+ Important changes
65
+ -----------------
66
+
67
+ ### 0.2.0
68
+
69
+ - Ed25519 is now named `Ed25519` in `EdDSANamedCurveTable`, and the previous public constant
70
+ (containing the older inaccurate name) has been removed.
71
+
72
+ Credits
73
+ -------
74
+
75
+ * The Ed25519 class was originally ported by k3d3 from [the Python Ed25519 reference implementation](https://ed25519.cr.yp.to/python/ed25519.py).
76
+ * Useful comments and tweaks were found in [the GNUnet implementation of Ed25519](https://gnunet.org/svn/gnunet-java/src/main/java/org/gnunet/util/crypto/) (based on k3d3's class).
77
+ * [BloodyRookie](https://github.com/BloodyRookie) reviewed the code, adding many useful comments, unit tests and literature.
@@ -0,0 +1,491 @@
1
+ /**
2
+ * EdDSA-Java by str4d
3
+ *
4
+ * To the extent possible under law, the person who associated CC0 with
5
+ * EdDSA-Java has waived all copyright and related or neighboring rights
6
+ * to EdDSA-Java.
7
+ *
8
+ * You should have received a copy of the CC0 legalcode along with this
9
+ * work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
10
+ *
11
+ */
12
+ package net.i2p.crypto.eddsa;
13
+
14
+ import java.io.ByteArrayOutputStream;
15
+ import java.nio.ByteBuffer;
16
+ import java.security.InvalidAlgorithmParameterException;
17
+ import java.security.InvalidKeyException;
18
+ import java.security.MessageDigest;
19
+ import java.security.NoSuchAlgorithmException;
20
+ import java.security.PrivateKey;
21
+ import java.security.PublicKey;
22
+ import java.security.Signature;
23
+ import java.security.SignatureException;
24
+ import java.security.spec.AlgorithmParameterSpec;
25
+ import java.security.spec.InvalidKeySpecException;
26
+ import java.security.spec.X509EncodedKeySpec;
27
+ import java.util.Arrays;
28
+
29
+ import net.i2p.crypto.eddsa.math.Curve;
30
+ import net.i2p.crypto.eddsa.math.GroupElement;
31
+ import net.i2p.crypto.eddsa.math.ScalarOps;
32
+ import sun.security.x509.X509Key;
33
+
34
+ /**
35
+ * Signing and verification for EdDSA.
36
+ *<p>
37
+ * The EdDSA sign and verify algorithms do not interact well with
38
+ * the Java Signature API, as one or more update() methods must be
39
+ * called before sign() or verify(). Using the standard API,
40
+ * this implementation must copy and buffer all data passed in
41
+ * via update().
42
+ *</p><p>
43
+ * This implementation offers two ways to avoid this copying,
44
+ * but only if all data to be signed or verified is available
45
+ * in a single byte array.
46
+ *</p><p>
47
+ *Option 1:
48
+ *</p><ol>
49
+ *<li>Call initSign() or initVerify() as usual.
50
+ *</li><li>Call setParameter(ONE_SHOT_MODE)
51
+ *</li><li>Call update(byte[]) or update(byte[], int, int) exactly once
52
+ *</li><li>Call sign() or verify() as usual.
53
+ *</li><li>If doing additional one-shot signs or verifies with this object, you must
54
+ * call setParameter(ONE_SHOT_MODE) each time
55
+ *</li></ol>
56
+ *
57
+ *<p>
58
+ *Option 2:
59
+ *</p><ol>
60
+ *<li>Call initSign() or initVerify() as usual.
61
+ *</li><li>Call one of the signOneShot() or verifyOneShot() methods.
62
+ *</li><li>If doing additional one-shot signs or verifies with this object,
63
+ * just call signOneShot() or verifyOneShot() again.
64
+ *</li></ol>
65
+ *
66
+ * @author str4d
67
+ *
68
+ */
69
+ public final class EdDSAEngine extends Signature {
70
+ public static final String SIGNATURE_ALGORITHM = "NONEwithEdDSA";
71
+
72
+ private MessageDigest digest;
73
+ private ByteArrayOutputStream baos;
74
+ private EdDSAKey key;
75
+ private boolean oneShotMode;
76
+ private byte[] oneShotBytes;
77
+ private int oneShotOffset;
78
+ private int oneShotLength;
79
+
80
+ /**
81
+ * To efficiently sign or verify data in one shot, pass this to setParameters()
82
+ * after initSign() or initVerify() but BEFORE THE FIRST AND ONLY
83
+ * update(data) or update(data, off, len). The data reference will be saved
84
+ * and then used in sign() or verify() without copying the data.
85
+ * Violate these rules and you will get a SignatureException.
86
+ */
87
+ public static final AlgorithmParameterSpec ONE_SHOT_MODE = new OneShotSpec();
88
+
89
+ private static class OneShotSpec implements AlgorithmParameterSpec {}
90
+
91
+ /**
92
+ * No specific EdDSA-internal hash requested, allows any EdDSA key.
93
+ */
94
+ public EdDSAEngine() {
95
+ super(SIGNATURE_ALGORITHM);
96
+ }
97
+
98
+ /**
99
+ * Specific EdDSA-internal hash requested, only matching keys will be allowed.
100
+ * @param digest the hash algorithm that keys must have to sign or verify.
101
+ */
102
+ public EdDSAEngine(MessageDigest digest) {
103
+ this();
104
+ this.digest = digest;
105
+ }
106
+
107
+ private void reset() {
108
+ if (digest != null)
109
+ digest.reset();
110
+ if (baos != null)
111
+ baos.reset();
112
+ oneShotMode = false;
113
+ oneShotBytes = null;
114
+ }
115
+
116
+ @Override
117
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
118
+ reset();
119
+ if (privateKey instanceof EdDSAPrivateKey) {
120
+ EdDSAPrivateKey privKey = (EdDSAPrivateKey) privateKey;
121
+ key = privKey;
122
+
123
+ if (digest == null) {
124
+ // Instantiate the digest from the key parameters
125
+ try {
126
+ digest = MessageDigest.getInstance(key.getParams().getHashAlgorithm());
127
+ } catch (NoSuchAlgorithmException e) {
128
+ throw new InvalidKeyException("cannot get required digest " + key.getParams().getHashAlgorithm() + " for private key.");
129
+ }
130
+ } else if (!key.getParams().getHashAlgorithm().equals(digest.getAlgorithm()))
131
+ throw new InvalidKeyException("Key hash algorithm does not match chosen digest");
132
+ digestInitSign(privKey);
133
+ } else {
134
+ throw new InvalidKeyException("cannot identify EdDSA private key: " + privateKey.getClass());
135
+ }
136
+ }
137
+
138
+ private void digestInitSign(EdDSAPrivateKey privKey) {
139
+ // Preparing for hash
140
+ // r = H(h_b,...,h_2b-1,M)
141
+ int b = privKey.getParams().getCurve().getField().getb();
142
+ digest.update(privKey.getH(), b/8, b/4 - b/8);
143
+ }
144
+
145
+ @Override
146
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
147
+ reset();
148
+ if (publicKey instanceof EdDSAPublicKey) {
149
+ key = (EdDSAPublicKey) publicKey;
150
+
151
+ if (digest == null) {
152
+ // Instantiate the digest from the key parameters
153
+ try {
154
+ digest = MessageDigest.getInstance(key.getParams().getHashAlgorithm());
155
+ } catch (NoSuchAlgorithmException e) {
156
+ throw new InvalidKeyException("cannot get required digest " + key.getParams().getHashAlgorithm() + " for private key.");
157
+ }
158
+ } else if (!key.getParams().getHashAlgorithm().equals(digest.getAlgorithm()))
159
+ throw new InvalidKeyException("Key hash algorithm does not match chosen digest");
160
+ } else if (publicKey instanceof X509Key) {
161
+ // X509Certificate will sometimes contain an X509Key rather than the EdDSAPublicKey itself; the contained
162
+ // key is valid but needs to be instanced as an EdDSAPublicKey before it can be used.
163
+ EdDSAPublicKey parsedPublicKey;
164
+ try {
165
+ parsedPublicKey = new EdDSAPublicKey(new X509EncodedKeySpec(publicKey.getEncoded()));
166
+ } catch (InvalidKeySpecException ex) {
167
+ throw new InvalidKeyException("cannot handle X.509 EdDSA public key: " + publicKey.getAlgorithm());
168
+ }
169
+ engineInitVerify(parsedPublicKey);
170
+ } else {
171
+ throw new InvalidKeyException("cannot identify EdDSA public key: " + publicKey.getClass());
172
+ }
173
+ }
174
+
175
+ /**
176
+ * @throws SignatureException if in one-shot mode
177
+ */
178
+ @Override
179
+ protected void engineUpdate(byte b) throws SignatureException {
180
+ if (oneShotMode)
181
+ throw new SignatureException("unsupported in one-shot mode");
182
+ if (baos == null)
183
+ baos = new ByteArrayOutputStream(256);
184
+ baos.write(b);
185
+ }
186
+
187
+ /**
188
+ * @throws SignatureException if one-shot rules are violated
189
+ */
190
+ @Override
191
+ protected void engineUpdate(byte[] b, int off, int len)
192
+ throws SignatureException {
193
+ if (oneShotMode) {
194
+ if (oneShotBytes != null)
195
+ throw new SignatureException("update() already called");
196
+ oneShotBytes = b;
197
+ oneShotOffset = off;
198
+ oneShotLength = len;
199
+ } else {
200
+ if (baos == null)
201
+ baos = new ByteArrayOutputStream(256);
202
+ baos.write(b, off, len);
203
+ }
204
+ }
205
+
206
+ @Override
207
+ protected byte[] engineSign() throws SignatureException {
208
+ try {
209
+ return x_engineSign();
210
+ } finally {
211
+ reset();
212
+ // must leave the object ready to sign again with
213
+ // the same key, as required by the API
214
+ EdDSAPrivateKey privKey = (EdDSAPrivateKey) key;
215
+ digestInitSign(privKey);
216
+ }
217
+ }
218
+
219
+ private byte[] x_engineSign() throws SignatureException {
220
+ Curve curve = key.getParams().getCurve();
221
+ ScalarOps sc = key.getParams().getScalarOps();
222
+ byte[] a = ((EdDSAPrivateKey) key).geta();
223
+
224
+ byte[] message;
225
+ int offset, length;
226
+ if (oneShotMode) {
227
+ if (oneShotBytes == null)
228
+ throw new SignatureException("update() not called first");
229
+ message = oneShotBytes;
230
+ offset = oneShotOffset;
231
+ length = oneShotLength;
232
+ } else {
233
+ if (baos == null)
234
+ message = new byte[0];
235
+ else
236
+ message = baos.toByteArray();
237
+ offset = 0;
238
+ length = message.length;
239
+ }
240
+ // r = H(h_b,...,h_2b-1,M)
241
+ digest.update(message, offset, length);
242
+ byte[] r = digest.digest();
243
+
244
+ // r mod l
245
+ // Reduces r from 64 bytes to 32 bytes
246
+ r = sc.reduce(r);
247
+
248
+ // R = rB
249
+ GroupElement R = key.getParams().getB().scalarMultiply(r);
250
+ byte[] Rbyte = R.toByteArray();
251
+
252
+ // S = (r + H(Rbar,Abar,M)*a) mod l
253
+ digest.update(Rbyte);
254
+ digest.update(((EdDSAPrivateKey) key).getAbyte());
255
+ digest.update(message, offset, length);
256
+ byte[] h = digest.digest();
257
+ h = sc.reduce(h);
258
+ byte[] S = sc.multiplyAndAdd(h, a, r);
259
+
260
+ // R+S
261
+ int b = curve.getField().getb();
262
+ ByteBuffer out = ByteBuffer.allocate(b/4);
263
+ out.put(Rbyte).put(S);
264
+ return out.array();
265
+ }
266
+
267
+ @Override
268
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
269
+ try {
270
+ return x_engineVerify(sigBytes);
271
+ } finally {
272
+ reset();
273
+ }
274
+ }
275
+
276
+ private boolean x_engineVerify(byte[] sigBytes) throws SignatureException {
277
+ Curve curve = key.getParams().getCurve();
278
+ int b = curve.getField().getb();
279
+ if (sigBytes.length != b/4)
280
+ throw new SignatureException("signature length is wrong");
281
+
282
+ // R is first b/8 bytes of sigBytes, S is second b/8 bytes
283
+ digest.update(sigBytes, 0, b/8);
284
+ digest.update(((EdDSAPublicKey) key).getAbyte());
285
+ // h = H(Rbar,Abar,M)
286
+ byte[] message;
287
+ int offset, length;
288
+ if (oneShotMode) {
289
+ if (oneShotBytes == null)
290
+ throw new SignatureException("update() not called first");
291
+ message = oneShotBytes;
292
+ offset = oneShotOffset;
293
+ length = oneShotLength;
294
+ } else {
295
+ if (baos == null)
296
+ message = new byte[0];
297
+ else
298
+ message = baos.toByteArray();
299
+ offset = 0;
300
+ length = message.length;
301
+ }
302
+ digest.update(message, offset, length);
303
+ byte[] h = digest.digest();
304
+
305
+ // h mod l
306
+ h = key.getParams().getScalarOps().reduce(h);
307
+
308
+ byte[] Sbyte = Arrays.copyOfRange(sigBytes, b/8, b/4);
309
+ // R = SB - H(Rbar,Abar,M)A
310
+ GroupElement R = key.getParams().getB().doubleScalarMultiplyVariableTime(
311
+ ((EdDSAPublicKey) key).getNegativeA(), h, Sbyte);
312
+
313
+ // Variable time. This should be okay, because there are no secret
314
+ // values used anywhere in verification.
315
+ byte[] Rcalc = R.toByteArray();
316
+ for (int i = 0; i < Rcalc.length; i++) {
317
+ if (Rcalc[i] != sigBytes[i])
318
+ return false;
319
+ }
320
+ return true;
321
+ }
322
+
323
+ /**
324
+ * To efficiently sign all the data in one shot, if it is available,
325
+ * use this method, which will avoid copying the data.
326
+ *
327
+ * Same as:
328
+ *<pre>
329
+ * setParameter(ONE_SHOT_MODE)
330
+ * update(data)
331
+ * sig = sign()
332
+ *</pre>
333
+ *
334
+ * @param data the message to be signed
335
+ * @return the signature
336
+ * @throws SignatureException if update() already called
337
+ * @see #ONE_SHOT_MODE
338
+ */
339
+ public byte[] signOneShot(byte[] data) throws SignatureException {
340
+ return signOneShot(data, 0, data.length);
341
+ }
342
+
343
+ /**
344
+ * To efficiently sign all the data in one shot, if it is available,
345
+ * use this method, which will avoid copying the data.
346
+ *
347
+ * Same as:
348
+ *<pre>
349
+ * setParameter(ONE_SHOT_MODE)
350
+ * update(data, off, len)
351
+ * sig = sign()
352
+ *</pre>
353
+ *
354
+ * @param data byte array containing the message to be signed
355
+ * @param off the start of the message inside data
356
+ * @param len the length of the message
357
+ * @return the signature
358
+ * @throws SignatureException if update() already called
359
+ * @see #ONE_SHOT_MODE
360
+ */
361
+ public byte[] signOneShot(byte[] data, int off, int len) throws SignatureException {
362
+ oneShotMode = true;
363
+ update(data, off, len);
364
+ return sign();
365
+ }
366
+
367
+ /**
368
+ * To efficiently verify all the data in one shot, if it is available,
369
+ * use this method, which will avoid copying the data.
370
+ *
371
+ * Same as:
372
+ *<pre>
373
+ * setParameter(ONE_SHOT_MODE)
374
+ * update(data)
375
+ * ok = verify(signature)
376
+ *</pre>
377
+ *
378
+ * @param data the message that was signed
379
+ * @param signature of the message
380
+ * @return true if the signature is valid, false otherwise
381
+ * @throws SignatureException if update() already called
382
+ * @see #ONE_SHOT_MODE
383
+ */
384
+ public boolean verifyOneShot(byte[] data, byte[] signature) throws SignatureException {
385
+ return verifyOneShot(data, 0, data.length, signature, 0, signature.length);
386
+ }
387
+
388
+ /**
389
+ * To efficiently verify all the data in one shot, if it is available,
390
+ * use this method, which will avoid copying the data.
391
+ *
392
+ * Same as:
393
+ *<pre>
394
+ * setParameter(ONE_SHOT_MODE)
395
+ * update(data, off, len)
396
+ * ok = verify(signature)
397
+ *</pre>
398
+ *
399
+ * @param data byte array containing the message that was signed
400
+ * @param off the start of the message inside data
401
+ * @param len the length of the message
402
+ * @param signature of the message
403
+ * @return true if the signature is valid, false otherwise
404
+ * @throws SignatureException if update() already called
405
+ * @see #ONE_SHOT_MODE
406
+ */
407
+ public boolean verifyOneShot(byte[] data, int off, int len, byte[] signature) throws SignatureException {
408
+ return verifyOneShot(data, off, len, signature, 0, signature.length);
409
+ }
410
+
411
+ /**
412
+ * To efficiently verify all the data in one shot, if it is available,
413
+ * use this method, which will avoid copying the data.
414
+ *
415
+ * Same as:
416
+ *<pre>
417
+ * setParameter(ONE_SHOT_MODE)
418
+ * update(data)
419
+ * ok = verify(signature, sigoff, siglen)
420
+ *</pre>
421
+ *
422
+ * @param data the message that was signed
423
+ * @param signature byte array containing the signature
424
+ * @param sigoff the start of the signature
425
+ * @param siglen the length of the signature
426
+ * @return true if the signature is valid, false otherwise
427
+ * @throws SignatureException if update() already called
428
+ * @see #ONE_SHOT_MODE
429
+ */
430
+ public boolean verifyOneShot(byte[] data, byte[] signature, int sigoff, int siglen) throws SignatureException {
431
+ return verifyOneShot(data, 0, data.length, signature, sigoff, siglen);
432
+ }
433
+
434
+ /**
435
+ * To efficiently verify all the data in one shot, if it is available,
436
+ * use this method, which will avoid copying the data.
437
+ *
438
+ * Same as:
439
+ *<pre>
440
+ * setParameter(ONE_SHOT_MODE)
441
+ * update(data, off, len)
442
+ * ok = verify(signature, sigoff, siglen)
443
+ *</pre>
444
+ *
445
+ * @param data byte array containing the message that was signed
446
+ * @param off the start of the message inside data
447
+ * @param len the length of the message
448
+ * @param signature byte array containing the signature
449
+ * @param sigoff the start of the signature
450
+ * @param siglen the length of the signature
451
+ * @return true if the signature is valid, false otherwise
452
+ * @throws SignatureException if update() already called
453
+ * @see #ONE_SHOT_MODE
454
+ */
455
+ public boolean verifyOneShot(byte[] data, int off, int len, byte[] signature, int sigoff, int siglen) throws SignatureException {
456
+ oneShotMode = true;
457
+ update(data, off, len);
458
+ return verify(signature, sigoff, siglen);
459
+ }
460
+
461
+ /**
462
+ * @throws InvalidAlgorithmParameterException if spec is ONE_SHOT_MODE and update() already called
463
+ * @see #ONE_SHOT_MODE
464
+ */
465
+ @Override
466
+ protected void engineSetParameter(AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException {
467
+ if (spec.equals(ONE_SHOT_MODE)) {
468
+ if (oneShotBytes != null || (baos != null && baos.size() > 0))
469
+ throw new InvalidAlgorithmParameterException("update() already called");
470
+ oneShotMode = true;
471
+ } else {
472
+ super.engineSetParameter(spec);
473
+ }
474
+ }
475
+
476
+ /**
477
+ * @deprecated
478
+ */
479
+ @Override
480
+ protected void engineSetParameter(String param, Object value) {
481
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
482
+ }
483
+
484
+ /**
485
+ * @deprecated
486
+ */
487
+ @Override
488
+ protected Object engineGetParameter(String param) {
489
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
490
+ }
491
+ }