· 6 years ago · Jul 30, 2019, 03:58 PM
1#include <catch.hpp>
2#include <chrono>
3#include <iomanip>
4#include <iostream>
5
6#include <jni/Array.h>
7#include <jni/JavaObject.h>
8#include <jni/Method.h>
9#include <jni/boxed.h>
10
11#include <java/lang/String.h>
12#include <java/security/SecureRandom.h>
13
14#include <java/lang/IllegalArgumentException.h>
15#include <java/security/InvalidAlgorithmParameterException.h>
16#include <java/security/InvalidKeyException.h>
17#include <java/security/NoSuchAlgorithmException.h>
18#include <java/security/NoSuchPaddingException.h>
19
20namespace jni {} // namespace jni
21
22namespace java {
23namespace security {
24
25class Key : public jni::JavaObject {
26public:
27 using jni::JavaObject::JavaObject;
28
29public:
30 virtual java::lang::String getAlgorithm() = 0;
31 virtual jni::ByteArray getEncoded() = 0;
32 virtual java::lang::String getFormat() = 0;
33};
34
35namespace spec {
36
37class AlgorithmParameterSpec : public jni::JavaObject {
38public:
39 using jni::JavaObject::JavaObject;
40};
41
42} // namespace spec
43
44} // namespace security
45} // namespace java
46
47namespace javax {
48namespace crypto {
49
50namespace spec {
51
52class SecretKeySpec : public java::security::Key {
53public:
54 using java::security::Key::Key;
55
56public:
57 SecretKeySpec(const jni::ByteArray &key,
58 const java::lang::String &algorithm) {
59 static auto cls = jni::get_class<SecretKeySpec>();
60 static auto method = jni::find_constructor<void(
61 const jni::ByteArray &, const java::lang::String &)>(*cls);
62 ref_ = method.execute<java::lang::IllegalArgumentException>(*cls, key,
63 algorithm);
64 }
65
66public:
67 java::lang::String getAlgorithm() override {
68 static auto cls = jni::get_class<SecretKeySpec>();
69 static auto method =
70 jni::find_class_method<java::lang::String()>(*cls, "getAlgorithm");
71 return method.execute<>(*this);
72 }
73
74 jni::ByteArray getEncoded() override {
75 static auto cls = jni::get_class<SecretKeySpec>();
76 static auto method =
77 jni::find_class_method<jni::ByteArray()>(*cls, "getEncoded");
78 return method.execute<>(*this);
79 }
80
81 java::lang::String getFormat() override {
82 static auto cls = jni::get_class<SecretKeySpec>();
83 static auto method =
84 jni::find_class_method<java::lang::String()>(*cls, "getFormat");
85 return method.execute<>(*this);
86 }
87
88public:
89 java::lang::String toString() override;
90};
91OMP_JNI_DECLARE_TO_STRING(SecretKeySpec)
92
93class GCMParameterSpec : public java::security::spec::AlgorithmParameterSpec {
94public:
95 using AlgorithmParameterSpec::AlgorithmParameterSpec;
96
97public:
98 GCMParameterSpec(jni::Int tLen, const jni::ByteArray &src) {
99 static auto cls = jni::get_class<GCMParameterSpec>();
100 static auto method =
101 jni::find_constructor<void(const jni::Int &, const jni::ByteArray &)>(
102 *cls);
103 ref_ =
104 method.execute<java::lang::IllegalArgumentException>(*cls, tLen, src);
105 }
106};
107
108} // namespace spec
109
110class Cipher : public jni::JavaObject {
111public:
112 const static ::jint DECRYPT_MODE = 2;
113 const static ::jint ENCRYPT_MODE = 1;
114 const static ::jint PRIVATE_KEY = 2;
115 const static ::jint PUBLIC_KEY = 1;
116 const static ::jint SECRET_KEY = 3;
117 const static ::jint UNWRAP_MODE = 4;
118 const static ::jint WRAP_MODE = 3;
119
120public:
121 using jni::JavaObject::JavaObject;
122
123public:
124 void init(jni::Int opmode, const java::security::Key &key) {
125 using namespace java::security;
126
127 static auto cls = jni::get_class<Cipher>();
128 static auto method =
129 jni::find_class_method<void(jni::Int, const java::security::Key &)>(
130 *cls, "init");
131 return method.execute<InvalidKeyException>(*this, opmode, key);
132 }
133
134 void init(jni::Int opmode,
135 const java::security::Key &key,
136 const java::security::spec::AlgorithmParameterSpec ¶ms) {
137 using namespace java::security;
138
139 static auto cls = jni::get_class<Cipher>();
140 static auto method = jni::find_class_method<void(
141 jni::Int, const java::security::Key &,
142 const java::security::spec::AlgorithmParameterSpec)>(*cls, "init");
143 return method
144 .execute<InvalidKeyException, InvalidAlgorithmParameterException>(
145 *this, opmode, key, params);
146 }
147
148public:
149 static Cipher getInstance(const java::lang::String &transformation) {
150 using namespace java::security;
151
152 static auto cls = jni::get_class<Cipher>();
153 static auto method =
154 jni::find_static_method<Cipher(const java::lang::String &)>(
155 *cls, "getInstance");
156 return method.execute<NoSuchAlgorithmException, NoSuchPaddingException,
157 GeneralSecurityException>(*cls, transformation);
158 }
159
160 java::lang::String getAlgorithm() {
161 static auto cls = jni::get_class<Cipher>();
162 static auto method =
163 jni::find_class_method<java::lang::String()>(*cls, "getAlgorithm");
164 return method.execute<>(*this);
165 }
166
167 jni::ByteArray getIV() {
168 static auto cls = jni::get_class<Cipher>();
169 static auto method =
170 jni::find_class_method<jni::ByteArray()>(*cls, "getIV");
171 return method.execute<>(*this);
172 }
173
174 jni::ByteArray doFinal(const jni::ByteArray &input) {
175 static auto cls = jni::get_class<Cipher>();
176 static auto method =
177 jni::find_class_method<jni::ByteArray(const jni::ByteArray &)>(
178 *cls, "doFinal");
179 return method.execute<>(*this, input);
180 }
181
182public:
183 java::lang::String toString() override;
184};
185
186OMP_JNI_DECLARE_TO_STRING(Cipher)
187
188} // namespace crypto
189} // namespace javax
190
191OMP_JNI_CLASS_DESCRIPTION(SecretKeySpec, javax, crypto, spec)
192OMP_JNI_CLASS_DESCRIPTION(GCMParameterSpec, javax, crypto, spec)
193
194OMP_JNI_CLASS_DESCRIPTION(Key, java, security)
195OMP_JNI_CLASS_DESCRIPTION(AlgorithmParameterSpec, java, security, spec)
196OMP_JNI_CLASS_DESCRIPTION(Cipher, javax, crypto)
197
198namespace {
199void print(const jni::ByteArray &array, bool text = false) {
200 auto cpp = array.get_array();
201 for (auto byte : cpp) {
202 if (text) {
203 std::cout << byte;
204 } else {
205 auto upcasted =
206 static_cast<std::uint32_t>(static_cast<std::uint8_t>(byte));
207 std::cout << std::setw(2) << std::setfill('0') << std::hex << upcasted
208 << " ";
209 }
210 }
211 std::cout << std::endl;
212}
213} // namespace
214
215TEST_CASE("DW Classes", "[DW]") {
216 jni::ByteArray plain_text{
217 {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}};
218 java::security::SecureRandom rnd;
219 jni::ByteArray key{16};
220 rnd.nextBytes(key);
221 javax::crypto::spec::SecretKeySpec crypt_spec{key, "AES"};
222
223 javax::crypto::Cipher crypt_cipher =
224 javax::crypto::Cipher::getInstance("AES/GCM/NoPadding");
225 crypt_cipher.init(javax::crypto::Cipher::ENCRYPT_MODE, crypt_spec);
226
227 auto iv = crypt_cipher.getIV();
228 auto encrypted = crypt_cipher.doFinal(plain_text);
229
230 // Decrypt data back
231 javax::crypto::Cipher decrypt_cipher =
232 javax::crypto::Cipher::getInstance("AES/GCM/NoPadding");
233 javax::crypto::spec::GCMParameterSpec decrypt_spec{128, iv};
234 decrypt_cipher.init(javax::crypto::Cipher::DECRYPT_MODE, crypt_spec,
235 decrypt_spec);
236 auto decrypted = decrypt_cipher.doFinal(encrypted);
237
238 print(plain_text, true);
239 print(key);
240 print(iv);
241 print(encrypted);
242 print(decrypted, true);
243}