Merge branch 'master' into 1.4
diff --git a/README.md b/README.md
index 50cde68..fe3db8e 100644
--- a/README.md
+++ b/README.md
@@ -111,7 +111,7 @@
released on 2020-05-14.
* [Java and Android](docs/JAVA-HOWTO.md), [C++](docs/CPP-HOWTO.md),
[Obj-C](docs/OBJC-HOWTO.md), [Go](docs/GOLANG-HOWTO.md), and
- [Python](g3docs/PYTHON-HOWTO.md) are field tested and ready for production.
+ [Python](docs/PYTHON-HOWTO.md) are field tested and ready for production.
* Tink for JavaScript is in active development.
## Learn more
diff --git a/apps/paymentmethodtoken/BUILD.bazel b/apps/paymentmethodtoken/BUILD.bazel
index 6dab6a1..6cc83f0 100644
--- a/apps/paymentmethodtoken/BUILD.bazel
+++ b/apps/paymentmethodtoken/BUILD.bazel
@@ -1,81 +1,23 @@
+load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
+
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
-load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "src/main/**/*.java",
- ],
- ),
-)
-
-java_library(
- name = "paymentmethodtoken",
- srcs = [":srcs"],
- javacopts = JAVACOPTS_OSS,
- deps = [
- "@tink_java//:java",
- "@tink_java//:subtle",
- "@maven//:com_google_http_client_google_http_client",
- "@maven//:joda_time_joda_time",
- "@maven//:org_json_json",
- ],
-)
-
-java_binary(
- name = "recipientkeygen",
- srcs = glob([
- "src/main/**/PaymentMethodTokenRecipientKeyGen.java",
- ]),
- javacopts = JAVACOPTS_OSS,
- main_class = "com.google.crypto.tink.apps.paymentmethodtoken.PaymentMethodTokenRecipientKeyGen",
- deps = [
- ":paymentmethodtoken",
- "@tink_java//:java",
- "@tink_java//:subtle",
- ],
-)
-
-# Maven Jars
-
-load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
-
gen_maven_jar_rules(
name = "maven",
doctitle = "Tink Cryptography API for Google Payment Method Token",
root_packages = ["com.google.crypto.tink.apps.paymentmethodtoken"],
- deps = [":paymentmethodtoken"],
-)
-
-# Tests
-
-load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
-
-java_library(
- name = "generator_test",
- testonly = 1,
- srcs = glob([
- "src/test/**/*.java",
- ]),
deps = [
- ":paymentmethodtoken",
- "@tink_java//:testonly",
- "@maven//:com_google_http_client_google_http_client",
- "@maven//:joda_time_joda_time",
- "@maven//:junit_junit",
- "@maven//:org_json_json",
- ],
-)
-
-gen_java_test_rules(
- test_files = glob([
- "src/test/**/*Test.java",
- ]),
- deps = [
- ":generator_test",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:google_payments_public_keys_manager",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_constants",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_hybrid_decrypt",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_hybrid_encrypt",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_recipient",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_recipient_kem",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_recipient_key_gen",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_sender",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_util",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:sender_intermediate_cert_factory",
],
)
diff --git a/apps/paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken/BUILD.bazel b/apps/paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken/BUILD.bazel
new file mode 100644
index 0000000..d7131c4
--- /dev/null
+++ b/apps/paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken/BUILD.bazel
@@ -0,0 +1,125 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+java_library(
+ name = "google_payments_public_keys_manager",
+ srcs = ["GooglePaymentsPublicKeysManager.java"],
+ deps = [
+ "@maven//:com_google_http_client_google_http_client",
+ "@tink_java//src/main/java/com/google/crypto/tink/util:keys_downloader",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_hybrid_decrypt",
+ srcs = ["PaymentMethodTokenHybridDecrypt.java"],
+ deps = [
+ ":payment_method_token_constants",
+ ":payment_method_token_recipient_kem",
+ ":payment_method_token_util",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:bytes",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:hkdf",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_sender",
+ srcs = ["PaymentMethodTokenSender.java"],
+ deps = [
+ ":payment_method_token_constants",
+ ":payment_method_token_hybrid_encrypt",
+ ":payment_method_token_util",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_sign",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_recipient_key_gen",
+ srcs = ["PaymentMethodTokenRecipientKeyGen.java"],
+ deps = [
+ ":payment_method_token_constants",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_constants",
+ srcs = ["PaymentMethodTokenConstants.java"],
+ deps = [
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:enums",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_recipient_kem",
+ srcs = ["PaymentMethodTokenRecipientKem.java"],
+)
+
+java_library(
+ name = "payment_method_token_hybrid_encrypt",
+ srcs = ["PaymentMethodTokenHybridEncrypt.java"],
+ deps = [
+ ":payment_method_token_constants",
+ ":payment_method_token_util",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecies_hkdf_sender_kem",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_recipient",
+ srcs = ["PaymentMethodTokenRecipient.java"],
+ deps = [
+ ":google_payments_public_keys_manager",
+ ":payment_method_token_constants",
+ ":payment_method_token_hybrid_decrypt",
+ ":payment_method_token_recipient_kem",
+ ":payment_method_token_util",
+ "@maven//:joda_time_joda_time",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecdsa_verify_jce",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+java_library(
+ name = "sender_intermediate_cert_factory",
+ srcs = ["SenderIntermediateCertFactory.java"],
+ deps = [
+ ":payment_method_token_constants",
+ ":payment_method_token_util",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_sign",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+java_library(
+ name = "payment_method_token_util",
+ srcs = ["PaymentMethodTokenUtil.java"],
+ deps = [
+ ":payment_method_token_constants",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:bytes",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ ],
+)
diff --git a/apps/paymentmethodtoken/src/test/BUILD.bazel b/apps/paymentmethodtoken/src/test/BUILD.bazel
new file mode 100644
index 0000000..3e552b2
--- /dev/null
+++ b/apps/paymentmethodtoken/src/test/BUILD.bazel
@@ -0,0 +1,44 @@
+load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+# Tests
+
+java_library(
+ name = "generator_test",
+ testonly = 1,
+ srcs = glob([
+ "**/*.java",
+ ]),
+ deps = [
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:google_payments_public_keys_manager",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_constants",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_hybrid_decrypt",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_hybrid_encrypt",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_recipient",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_recipient_kem",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_sender",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:payment_method_token_util",
+ "//paymentmethodtoken/src/main/java/com/google/crypto/tink/apps/paymentmethodtoken:sender_intermediate_cert_factory",
+ "@maven//:com_google_http_client_google_http_client",
+ "@maven//:joda_time_joda_time",
+ "@maven//:junit_junit",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:random",
+ ],
+)
+
+gen_java_test_rules(
+ test_files = glob([
+ "**/*Test.java",
+ ]),
+ deps = [
+ ":generator_test",
+ ],
+)
diff --git a/apps/rewardedads/BUILD.bazel b/apps/rewardedads/BUILD.bazel
index 44b0c56..6efa5c9 100644
--- a/apps/rewardedads/BUILD.bazel
+++ b/apps/rewardedads/BUILD.bazel
@@ -1,65 +1,12 @@
+load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
+
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
-load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "src/main/**/*.java",
- ],
- ),
-)
-
-java_library(
- name = "rewardedads",
- srcs = [":srcs"],
- javacopts = JAVACOPTS_OSS,
- deps = [
- "@tink_java//:java",
- "@tink_java//:subtle",
- "@maven//:com_google_http_client_google_http_client",
- "@maven//:org_json_json",
- ],
-)
-
-# Maven Jars
-
-load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
-
gen_maven_jar_rules(
name = "maven",
doctitle = "Tink Cryptography API for Google Mobile Rewarded Video Ads SSV",
root_packages = ["com.google.crypto.tink.apps.rewardedads"],
- deps = [":rewardedads"],
-)
-
-# Tests
-
-load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
-
-java_library(
- name = "generator_test",
- testonly = 1,
- srcs = glob([
- "src/test/**/*.java",
- ]),
- deps = [
- ":rewardedads",
- "@tink_java//:testonly",
- "@maven//:com_google_http_client_google_http_client",
- "@maven//:junit_junit",
- "@maven//:org_json_json",
- ],
-)
-
-gen_java_test_rules(
- test_files = glob([
- "src/test/**/*Test.java",
- ]),
- deps = [
- ":generator_test",
- ],
+ deps = ["//rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads:rewarded_ads_verifier"],
)
diff --git a/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/BUILD.bazel b/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/BUILD.bazel
new file mode 100644
index 0000000..53784c5
--- /dev/null
+++ b/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/BUILD.bazel
@@ -0,0 +1,17 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+java_library(
+ name = "rewarded_ads_verifier",
+ srcs = ["RewardedAdsVerifier.java"],
+ deps = [
+ "@maven//:com_google_http_client_google_http_client",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecdsa_verify_jce",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:enums",
+ "@tink_java//src/main/java/com/google/crypto/tink/util:keys_downloader",
+ ],
+)
diff --git a/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java b/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
index 3448368..1cd1c86 100644
--- a/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
+++ b/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
@@ -65,6 +65,8 @@
* Builder also allows you to customize other properties.
*/
public final class RewardedAdsVerifier {
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
/** Default HTTP transport used by this class. */
private static final NetHttpTransport DEFAULT_HTTP_TRANSPORT =
new NetHttpTransport.Builder().build();
@@ -85,13 +87,13 @@
/**
* Instance configured to talk to fetch keys from production environment (from {@link
- * KeysDownloader#PUBLIC_KEYS_URL_PROD}).
+ * #PUBLIC_KEYS_URL_PROD}).
*/
public static final KeysDownloader KEYS_DOWNLOADER_INSTANCE_PROD =
new KeysDownloader(DEFAULT_BACKGROUND_EXECUTOR, DEFAULT_HTTP_TRANSPORT, PUBLIC_KEYS_URL_PROD);
/**
* Instance configured to talk to fetch keys from test environment (from {@link
- * KeysDownloader#KEYS_URL_TEST}).
+ * #PUBLIC_KEYS_URL_TEST}).
*/
public static final KeysDownloader KEYS_DOWNLOADER_INSTANCE_TEST =
new KeysDownloader(DEFAULT_BACKGROUND_EXECUTOR, DEFAULT_HTTP_TRANSPORT, PUBLIC_KEYS_URL_TEST);
@@ -130,9 +132,7 @@
"signature and key id must be the last two query parameters");
}
byte[] tbsData =
- queryString
- .substring(0, i - 1 /* i - 1 instead of i because of & */)
- .getBytes(Charset.forName("UTF-8"));
+ queryString.substring(0, i - 1 /* i - 1 instead of i because of & */).getBytes(UTF_8);
String sigAndKeyId = queryString.substring(i);
i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
@@ -174,7 +174,7 @@
/** Builder for RewardedAdsVerifier. */
public static class Builder {
private final List<VerifyingPublicKeysProvider> verifyingPublicKeysProviders =
- new ArrayList<VerifyingPublicKeysProvider>();
+ new ArrayList<>();
public Builder() {}
diff --git a/apps/rewardedads/src/test/BUILD.bazel b/apps/rewardedads/src/test/BUILD.bazel
new file mode 100644
index 0000000..796a3e0
--- /dev/null
+++ b/apps/rewardedads/src/test/BUILD.bazel
@@ -0,0 +1,35 @@
+load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+# Tests
+
+java_library(
+ name = "generator_test",
+ testonly = 1,
+ srcs = glob([
+ "**/*.java",
+ ]),
+ deps = [
+ "//rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads:rewarded_ads_verifier",
+ "@maven//:com_google_http_client_google_http_client",
+ "@maven//:junit_junit",
+ "@maven//:org_json_json",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:enums",
+ "@tink_java//src/main/java/com/google/crypto/tink/util:keys_downloader",
+ ],
+)
+
+gen_java_test_rules(
+ test_files = glob([
+ "**/*Test.java",
+ ]),
+ deps = [
+ ":generator_test",
+ ],
+)
diff --git a/apps/webpush/BUILD.bazel b/apps/webpush/BUILD.bazel
index 06218e6..8055fad 100644
--- a/apps/webpush/BUILD.bazel
+++ b/apps/webpush/BUILD.bazel
@@ -1,54 +1,17 @@
+load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
+
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
-load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
-java_library(
- name = "webpush",
- srcs = glob([
- "src/main/**/*.java",
- ]),
- javacopts = JAVACOPTS_OSS,
- deps = [
- "@tink_java//:java",
- "@tink_java//:subtle",
- ],
-)
-
-# Maven Jars
-
-load("@tink_java//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
-
gen_maven_jar_rules(
name = "maven",
doctitle = "Tink Cryptography API for Message Encryption for Web Push (RFC 8291)",
root_packages = ["com.google.crypto.tink.apps.webpush"],
- deps = [":webpush"],
-)
-
-# Tests
-
-load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
-
-java_library(
- name = "generator_test",
- testonly = 1,
- srcs = glob([
- "src/test/**/*.java",
- ]),
deps = [
- ":webpush",
- "@tink_java//:testonly",
- "@maven//:junit_junit",
- ],
-)
-
-gen_java_test_rules(
- test_files = glob([
- "src/test/**/*Test.java",
- ]),
- deps = [
- ":generator_test",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_constants",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_hybrid_decrypt",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_hybrid_encrypt",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_util",
],
)
diff --git a/apps/webpush/src/main/java/com/google/crypto/tink/apps/webpush/BUILD.bazel b/apps/webpush/src/main/java/com/google/crypto/tink/apps/webpush/BUILD.bazel
new file mode 100644
index 0000000..5d2afbb
--- /dev/null
+++ b/apps/webpush/src/main/java/com/google/crypto/tink/apps/webpush/BUILD.bazel
@@ -0,0 +1,44 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+java_library(
+ name = "web_push_hybrid_decrypt",
+ srcs = ["WebPushHybridDecrypt.java"],
+ deps = [
+ ":web_push_constants",
+ ":web_push_util",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ ],
+)
+
+java_library(
+ name = "web_push_util",
+ srcs = ["WebPushUtil.java"],
+ deps = [
+ ":web_push_constants",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:bytes",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:hkdf",
+ ],
+)
+
+java_library(
+ name = "web_push_constants",
+ srcs = ["WebPushConstants.java"],
+ deps = ["@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves"],
+)
+
+java_library(
+ name = "web_push_hybrid_encrypt",
+ srcs = ["WebPushHybridEncrypt.java"],
+ deps = [
+ ":web_push_constants",
+ ":web_push_util",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:random",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ ],
+)
diff --git a/apps/webpush/src/test/BUILD.bazel b/apps/webpush/src/test/BUILD.bazel
new file mode 100644
index 0000000..309b3ad
--- /dev/null
+++ b/apps/webpush/src/test/BUILD.bazel
@@ -0,0 +1,38 @@
+load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+# Tests
+
+java_library(
+ name = "generator_test",
+ testonly = 1,
+ srcs = glob([
+ "**/*.java",
+ ]),
+ deps = [
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_constants",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_hybrid_decrypt",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_hybrid_encrypt",
+ "//webpush/src/main/java/com/google/crypto/tink/apps/webpush:web_push_util",
+ "@maven//:junit_junit",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:hex",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:random",
+ "@tink_java//src/main/java/com/google/crypto/tink/testing:test_util",
+ ],
+)
+
+gen_java_test_rules(
+ test_files = glob([
+ "**/*Test.java",
+ ]),
+ deps = [
+ ":generator_test",
+ ],
+)
diff --git a/apps/webpush/src/test/java/com/google/crypto/tink/apps/webpush/WebPushHybridEncryptTest.java b/apps/webpush/src/test/java/com/google/crypto/tink/apps/webpush/WebPushHybridEncryptTest.java
index 7db5059..7b84b84 100644
--- a/apps/webpush/src/test/java/com/google/crypto/tink/apps/webpush/WebPushHybridEncryptTest.java
+++ b/apps/webpush/src/test/java/com/google/crypto/tink/apps/webpush/WebPushHybridEncryptTest.java
@@ -25,6 +25,7 @@
import com.google.crypto.tink.subtle.EllipticCurves;
import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.subtle.Random;
+import com.google.crypto.tink.testing.TestUtil;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
@@ -41,59 +42,60 @@
public class WebPushHybridEncryptTest {
@Test
public void testEncryptDecrypt() throws Exception {
- for (int i = 0; i < 10; i++) {
- KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE);
- ECPrivateKey uaPrivateKey = (ECPrivateKey) uaKeyPair.getPrivate();
- ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
- byte[] uaPublicKeyBytes =
- EllipticCurves.pointEncode(
- WebPushConstants.NIST_P256_CURVE_TYPE,
- WebPushConstants.UNCOMPRESSED_POINT_FORMAT,
- uaPublicKey.getW());
- byte[] authSecret = Random.randBytes(16);
- HybridEncrypt hybridEncrypt =
- new WebPushHybridEncrypt.Builder()
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKeyBytes)
- .build();
- HybridDecrypt hybridDecrypt =
- new WebPushHybridDecrypt.Builder()
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKeyBytes)
- .withRecipientPrivateKey(uaPrivateKey)
- .build();
+ KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE);
+ ECPrivateKey uaPrivateKey = (ECPrivateKey) uaKeyPair.getPrivate();
+ ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
+ byte[] uaPublicKeyBytes =
+ EllipticCurves.pointEncode(
+ WebPushConstants.NIST_P256_CURVE_TYPE,
+ WebPushConstants.UNCOMPRESSED_POINT_FORMAT,
+ uaPublicKey.getW());
+ byte[] authSecret = Random.randBytes(16);
+ HybridEncrypt hybridEncrypt =
+ new WebPushHybridEncrypt.Builder()
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKeyBytes)
+ .build();
+ HybridDecrypt hybridDecrypt =
+ new WebPushHybridDecrypt.Builder()
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKeyBytes)
+ .withRecipientPrivateKey(uaPrivateKey)
+ .build();
- Set<String> salts = new TreeSet<String>();
- Set<String> ephemeralPublicKeys = new TreeSet<String>();
- Set<String> payloads = new TreeSet<String>();
- int numTests = 50;
- for (int j = 0; j < numTests; j++) {
- byte[] plaintext = Random.randBytes(j);
- byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
- assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
- assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
-
- // Checks that the encryption is randomized.
- ByteBuffer record = ByteBuffer.wrap(ciphertext);
- byte[] salt = new byte[WebPushConstants.SALT_SIZE];
- record.get(salt);
- salts.add(Hex.encode(salt));
-
- int unused1 = record.getInt();
- int unused2 = (int) record.get();
-
- byte[] ephemeralPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE];
- record.get(ephemeralPublicKey);
- ephemeralPublicKeys.add(Hex.encode(ephemeralPublicKey));
-
- byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE];
- record.get(payload);
- payloads.add(Hex.encode(payload));
- }
- assertEquals(numTests, salts.size());
- assertEquals(numTests, ephemeralPublicKeys.size());
- assertEquals(numTests, payloads.size());
+ Set<String> salts = new TreeSet<>();
+ Set<String> ephemeralPublicKeys = new TreeSet<>();
+ Set<String> payloads = new TreeSet<>();
+ int numTests = 100;
+ if (TestUtil.isTsan()) {
+ numTests = 5;
}
+ for (int j = 0; j < numTests; j++) {
+ byte[] plaintext = Random.randBytes(j);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
+ assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
+ assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
+
+ // Checks that the encryption is randomized.
+ ByteBuffer record = ByteBuffer.wrap(ciphertext);
+ byte[] salt = new byte[WebPushConstants.SALT_SIZE];
+ record.get(salt);
+ salts.add(Hex.encode(salt));
+
+ int unused1 = record.getInt();
+ int unused2 = (int) record.get();
+
+ byte[] ephemeralPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE];
+ record.get(ephemeralPublicKey);
+ ephemeralPublicKeys.add(Hex.encode(ephemeralPublicKey));
+
+ byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE];
+ record.get(payload);
+ payloads.add(Hex.encode(payload));
+ }
+ assertEquals(numTests, salts.size());
+ assertEquals(numTests, ephemeralPublicKeys.size());
+ assertEquals(numTests, payloads.size());
}
@Test
@@ -103,101 +105,117 @@
ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
byte[] authSecret = Random.randBytes(16);
+ int numTests = 100;
+ if (TestUtil.isTsan()) {
+ numTests = 5;
+ }
// Test with random, valid record sizes.
- {
- for (int i = 0; i < 100; i++) {
- int recordSize =
- WebPushConstants.CIPHERTEXT_OVERHEAD
- + Random.randInt(
- WebPushConstants.MAX_CIPHERTEXT_SIZE - WebPushConstants.CIPHERTEXT_OVERHEAD);
- HybridEncrypt hybridEncrypt =
- new WebPushHybridEncrypt.Builder()
- .withRecordSize(recordSize)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .build();
- HybridDecrypt hybridDecrypt =
- new WebPushHybridDecrypt.Builder()
- .withRecordSize(recordSize)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .withRecipientPrivateKey(uaPrivateKey)
- .build();
+ for (int i = 0; i < numTests; i++) {
+ int recordSize =
+ WebPushConstants.CIPHERTEXT_OVERHEAD
+ + Random.randInt(
+ WebPushConstants.MAX_CIPHERTEXT_SIZE - WebPushConstants.CIPHERTEXT_OVERHEAD);
+ HybridEncrypt hybridEncrypt =
+ new WebPushHybridEncrypt.Builder()
+ .withRecordSize(recordSize)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .build();
+ HybridDecrypt hybridDecrypt =
+ new WebPushHybridDecrypt.Builder()
+ .withRecordSize(recordSize)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .withRecipientPrivateKey(uaPrivateKey)
+ .build();
- byte[] plaintext = Random.randBytes(recordSize - WebPushConstants.CIPHERTEXT_OVERHEAD);
- byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
- assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
- assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
- }
+ byte[] plaintext = Random.randBytes(recordSize - WebPushConstants.CIPHERTEXT_OVERHEAD);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
+ assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
+ assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
}
+ }
+ @Test
+ public void testEncryptDecrypt_largestPossibleRecordSize() throws Exception {
+ KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE);
+ ECPrivateKey uaPrivateKey = (ECPrivateKey) uaKeyPair.getPrivate();
+ ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
+ byte[] authSecret = Random.randBytes(16);
// Test with largest possible record size.
- {
- HybridEncrypt hybridEncrypt =
- new WebPushHybridEncrypt.Builder()
- .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .build();
- HybridDecrypt hybridDecrypt =
- new WebPushHybridDecrypt.Builder()
- .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .withRecipientPrivateKey(uaPrivateKey)
- .build();
- byte[] plaintext =
- Random.randBytes(
- WebPushConstants.MAX_CIPHERTEXT_SIZE - WebPushConstants.CIPHERTEXT_OVERHEAD);
- byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
- assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
- assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
- }
+ HybridEncrypt hybridEncrypt =
+ new WebPushHybridEncrypt.Builder()
+ .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .build();
+ HybridDecrypt hybridDecrypt =
+ new WebPushHybridDecrypt.Builder()
+ .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .withRecipientPrivateKey(uaPrivateKey)
+ .build();
+ byte[] plaintext =
+ Random.randBytes(
+ WebPushConstants.MAX_CIPHERTEXT_SIZE - WebPushConstants.CIPHERTEXT_OVERHEAD);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
+ assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
+ assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
+ }
+ @Test
+ public void testEncryptDecrypt_smallestPossibleRecordSize() throws Exception {
+ KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE);
+ ECPrivateKey uaPrivateKey = (ECPrivateKey) uaKeyPair.getPrivate();
+ ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
+ byte[] authSecret = Random.randBytes(16);
// Test with smallest possible record size.
- {
- HybridEncrypt hybridEncrypt =
- new WebPushHybridEncrypt.Builder()
- .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .build();
- HybridDecrypt hybridDecrypt =
- new WebPushHybridDecrypt.Builder()
- .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .withRecipientPrivateKey(uaPrivateKey)
- .build();
- byte[] plaintext = new byte[0];
- byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
- assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
- assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
+ HybridEncrypt hybridEncrypt =
+ new WebPushHybridEncrypt.Builder()
+ .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .build();
+ HybridDecrypt hybridDecrypt =
+ new WebPushHybridDecrypt.Builder()
+ .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .withRecipientPrivateKey(uaPrivateKey)
+ .build();
+ byte[] plaintext = new byte[0];
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null /* contextInfo */);
+ assertEquals(ciphertext.length, plaintext.length + WebPushConstants.CIPHERTEXT_OVERHEAD);
+ assertArrayEquals(plaintext, hybridDecrypt.decrypt(ciphertext, null /* contextInfo */));
+ }
+
+ @Test
+ public void testEncryptDecrypt_outOfRangeRecordSize_throws() throws Exception {
+ KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE);
+ ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic();
+ byte[] authSecret = Random.randBytes(16);
+
+ try {
+ new WebPushHybridEncrypt.Builder()
+ .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE + 1)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .build();
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // expected.
}
- // Test with out of range record sizes.
- {
- try {
- new WebPushHybridEncrypt.Builder()
- .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE + 1)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .build();
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException ex) {
- // expected.
- }
-
- try {
- new WebPushHybridEncrypt.Builder()
- .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD - 1)
- .withAuthSecret(authSecret)
- .withRecipientPublicKey(uaPublicKey)
- .build();
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException ex) {
- // expected.
- }
+ try {
+ new WebPushHybridEncrypt.Builder()
+ .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD - 1)
+ .withAuthSecret(authSecret)
+ .withRecipientPublicKey(uaPublicKey)
+ .build();
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // expected.
}
}
@@ -223,3 +241,4 @@
}
}
}
+
diff --git a/cc/CMakeLists.txt b/cc/CMakeLists.txt
index 32e6596..ebf68e0 100644
--- a/cc/CMakeLists.txt
+++ b/cc/CMakeLists.txt
@@ -11,6 +11,12 @@
tink_module(core)
+# configuration settings for the build
+option(USE_ONLY_FIPS "Enables the FIPS only mode in Tink" OFF)
+if(USE_ONLY_FIPS)
+ add_definitions(-DTINK_USE_ONLY_FIPS)
+endif()
+
# public libraries
set(TINK_VERSION_H "${TINK_GENFILE_DIR}/tink/version.h")
diff --git a/cc/aead/BUILD.bazel b/cc/aead/BUILD.bazel
index a952f93..68b986a 100644
--- a/cc/aead/BUILD.bazel
+++ b/cc/aead/BUILD.bazel
@@ -68,6 +68,7 @@
":kms_envelope_aead_key_manager",
":xchacha20_poly1305_key_manager",
"//config:config_util",
+ "//config:tink_fips",
"//mac:mac_config",
"//proto:config_cc_proto",
"//util:status",
@@ -141,6 +142,8 @@
"//:aead",
"//:core/key_type_manager",
"//:key_manager",
+ "//aead:cord_aead",
+ "//aead/internal:cord_aes_gcm_boringssl",
"//proto:aes_gcm_cc_proto",
"//proto:tink_cc_proto",
"//subtle:aes_gcm_boringssl",
@@ -421,6 +424,8 @@
deps = [
":aes_gcm_key_manager",
"//:aead",
+ "//aead:cord_aead",
+ "//aead/internal:cord_aes_gcm_boringssl",
"//proto:aes_gcm_cc_proto",
"//subtle:aead_test_util",
"//util:istream_input_stream",
diff --git a/cc/aead/CMakeLists.txt b/cc/aead/CMakeLists.txt
index 9352440..8709c95 100644
--- a/cc/aead/CMakeLists.txt
+++ b/cc/aead/CMakeLists.txt
@@ -63,6 +63,7 @@
tink::aead::xchacha20_poly1305_key_manager
tink::aead::aead_wrapper
tink::config::config_util
+ tink::config::tink_fips
tink::mac::mac_config
tink::util::status
tink::proto::config_cc_proto
@@ -128,6 +129,8 @@
SRCS
aes_gcm_key_manager.h
DEPS
+ tink::aead::cord_aead
+ tink::aead::internal::cord_aes_gcm_boringssl
tink::core::aead
tink::core::key_manager
tink::core::key_type_manager
@@ -378,6 +381,8 @@
SRCS aes_gcm_key_manager_test.cc
DEPS
tink::aead::aes_gcm_key_manager
+ tink::aead::cord_aead
+ tink::aead::internal::cord_aes_gcm_boringssl
tink::core::aead
tink::subtle::aead_test_util
tink::util::istream_input_stream
diff --git a/cc/aead/aead_config.cc b/cc/aead/aead_config.cc
index dc18d80..f64eaff 100644
--- a/cc/aead/aead_config.cc
+++ b/cc/aead/aead_config.cc
@@ -30,6 +30,7 @@
#include "tink/registry.h"
#include "tink/util/status.h"
#include "proto/config.pb.h"
+#include "tink/config/tink_fips.h"
using google::crypto::tink::RegistryConfig;
@@ -47,13 +48,24 @@
auto status = MacConfig::Register();
if (!status.ok()) return status;
- // Register key managers.
+ // Register primitive wrapper.
+ status = Registry::RegisterPrimitiveWrapper(absl::make_unique<AeadWrapper>());
+ if (!status.ok()) return status;
+
+ // Register key managers which utilize the FIPS validated BoringCrypto
+ // implementations.
status = Registry::RegisterKeyTypeManager(
absl::make_unique<AesCtrHmacAeadKeyManager>(), true);
if (!status.ok()) return status;
status = Registry::RegisterKeyTypeManager(
absl::make_unique<AesGcmKeyManager>(), true);
if (!status.ok()) return status;
+
+ if (kUseOnlyFips) {
+ return util::OkStatus();
+ }
+
+ // Register all the other key managers.
status = Registry::RegisterKeyTypeManager(
absl::make_unique<AesGcmSivKeyManager>(), true);
if (!status.ok()) return status;
@@ -70,9 +82,11 @@
absl::make_unique<KmsEnvelopeAeadKeyManager>(), true);
if (!status.ok()) return status;
- // Register primitive wrapper.
- return Registry::RegisterPrimitiveWrapper(absl::make_unique<AeadWrapper>());
+ return util::OkStatus();
}
+
+
+
} // namespace tink
} // namespace crypto
diff --git a/cc/aead/aead_config_test.cc b/cc/aead/aead_config_test.cc
index 9ad96e3..61325d0 100644
--- a/cc/aead/aead_config_test.cc
+++ b/cc/aead/aead_config_test.cc
@@ -16,6 +16,8 @@
#include "tink/aead/aead_config.h"
+#include <list>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "tink/aead.h"
@@ -24,10 +26,12 @@
#include "tink/config.h"
#include "tink/keyset_handle.h"
#include "tink/registry.h"
+#include "tink/config/tink_fips.h"
#include "tink/util/status.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
+
namespace crypto {
namespace tink {
namespace {
@@ -55,6 +59,10 @@
// Tests that the AeadWrapper has been properly registered and we can wrap
// primitives.
TEST_F(AeadConfigTest, WrappersRegistered) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
ASSERT_TRUE(AeadConfig::Register().ok());
google::crypto::tink::Keyset::Key key;
@@ -84,6 +92,47 @@
EXPECT_FALSE(decryption_result.status().ok());
}
+// FIPS-only mode tests
+TEST_F(AeadConfigTest, RegisterNonFipsTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(AeadConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
+ non_fips_key_templates.push_back(AeadKeyTemplates::Aes128Eax());
+ non_fips_key_templates.push_back(AeadKeyTemplates::Aes256Eax());
+ non_fips_key_templates.push_back(AeadKeyTemplates::Aes128GcmSiv());
+ non_fips_key_templates.push_back(AeadKeyTemplates::Aes256GcmSiv());
+ non_fips_key_templates.push_back(AeadKeyTemplates::XChaCha20Poly1305());
+
+ for (auto key_template : non_fips_key_templates) {
+ auto new_keyset_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_THAT(new_keyset_handle_result.status(),
+ StatusIs(util::error::NOT_FOUND));
+ }
+}
+
+TEST_F(AeadConfigTest, RegisterFipsValidTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(AeadConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> fips_key_templates;
+ fips_key_templates.push_back(AeadKeyTemplates::Aes128Gcm());
+ fips_key_templates.push_back(AeadKeyTemplates::Aes256Gcm());
+ fips_key_templates.push_back(AeadKeyTemplates::Aes128CtrHmacSha256());
+ fips_key_templates.push_back(AeadKeyTemplates::Aes256CtrHmacSha256());
+
+ for (auto key_template : fips_key_templates) {
+ auto new_keyset_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_THAT(new_keyset_handle_result.status(), IsOk());
+ }
+}
+
} // namespace
} // namespace tink
} // namespace crypto
diff --git a/cc/aead/aes_ctr_hmac_aead_key_manager.cc b/cc/aead/aes_ctr_hmac_aead_key_manager.cc
index 7c1af3c..645b574 100644
--- a/cc/aead/aes_ctr_hmac_aead_key_manager.cc
+++ b/cc/aead/aes_ctr_hmac_aead_key_manager.cc
@@ -102,6 +102,9 @@
Status status = ValidateVersion(key.version(), get_version());
if (!status.ok()) return status;
+ status = ValidateVersion(key.aes_ctr_key().version(), get_version());
+ if (!status.ok()) return status;
+
// Validate AesCtrKey.
auto aes_ctr_key = key.aes_ctr_key();
uint32_t aes_key_size = aes_ctr_key.key_value().size();
diff --git a/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc b/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc
index ddf6210..b3f72dc 100644
--- a/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc
+++ b/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc
@@ -208,8 +208,8 @@
key.hmac_key().params().tag_size());
ASSERT_THAT(direct_aead_or.status(), IsOk());
- EXPECT_THAT(EncryptThenDecrypt(aead_or.ValueOrDie().get(),
- direct_aead_or.ValueOrDie().get(),
+ EXPECT_THAT(EncryptThenDecrypt(*aead_or.ValueOrDie(),
+ *direct_aead_or.ValueOrDie(),
"message", "aad"),
IsOk());
}
diff --git a/cc/aead/aes_eax_key_manager_test.cc b/cc/aead/aes_eax_key_manager_test.cc
index d1f8a14..fdf9695 100644
--- a/cc/aead/aes_eax_key_manager_test.cc
+++ b/cc/aead/aes_eax_key_manager_test.cc
@@ -184,8 +184,8 @@
key_or.ValueOrDie().params().iv_size());
ASSERT_THAT(boring_ssl_aead_or.status(), IsOk());
- ASSERT_THAT(EncryptThenDecrypt(aead_or.ValueOrDie().get(),
- boring_ssl_aead_or.ValueOrDie().get(),
+ ASSERT_THAT(EncryptThenDecrypt(*aead_or.ValueOrDie(),
+ *boring_ssl_aead_or.ValueOrDie(),
"message", "aad"),
IsOk());
}
diff --git a/cc/aead/aes_gcm_key_manager.h b/cc/aead/aes_gcm_key_manager.h
index 94d5659..ed850b5 100644
--- a/cc/aead/aes_gcm_key_manager.h
+++ b/cc/aead/aes_gcm_key_manager.h
@@ -22,6 +22,8 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "tink/aead.h"
+#include "tink/aead/cord_aead.h"
+#include "tink/aead/internal/cord_aes_gcm_boringssl.h"
#include "tink/core/key_type_manager.h"
#include "tink/key_manager.h"
#include "tink/subtle/aes_gcm_boringssl.h"
@@ -42,7 +44,8 @@
class AesGcmKeyManager
: public KeyTypeManager<google::crypto::tink::AesGcmKey,
- google::crypto::tink::AesGcmKeyFormat, List<Aead>> {
+ google::crypto::tink::AesGcmKeyFormat,
+ List<Aead, CordAead>> {
public:
class AeadFactory : public PrimitiveFactory<Aead> {
crypto::tink::util::StatusOr<std::unique_ptr<Aead>> Create(
@@ -53,9 +56,20 @@
return {std::move(aes_gcm_result.ValueOrDie())};
}
};
+ class CordAeadFactory : public PrimitiveFactory<CordAead> {
+ crypto::tink::util::StatusOr<std::unique_ptr<CordAead>> Create(
+ const google::crypto::tink::AesGcmKey& key) const override {
+ auto cord_aes_gcm_result = crypto::tink::CordAesGcmBoringSsl::New(
+ util::SecretDataFromStringView(key.key_value()));
+ if (!cord_aes_gcm_result.ok()) return cord_aes_gcm_result.status();
+ return {std::move(cord_aes_gcm_result.ValueOrDie())};
+ }
+ };
AesGcmKeyManager()
- : KeyTypeManager(absl::make_unique<AesGcmKeyManager::AeadFactory>()) {}
+ : KeyTypeManager(absl::make_unique<AesGcmKeyManager::AeadFactory>(),
+ absl::make_unique<AesGcmKeyManager::CordAeadFactory>()) {
+ }
// Returns the version of this key manager.
uint32_t get_version() const override { return 0; }
diff --git a/cc/aead/aes_gcm_key_manager_test.cc b/cc/aead/aes_gcm_key_manager_test.cc
index 458339f..397b98b 100644
--- a/cc/aead/aes_gcm_key_manager_test.cc
+++ b/cc/aead/aes_gcm_key_manager_test.cc
@@ -19,6 +19,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "tink/aead.h"
+#include "tink/aead/internal/cord_aes_gcm_boringssl.h"
#include "tink/subtle/aead_test_util.h"
#include "tink/util/istream_input_stream.h"
#include "tink/util/secret_data.h"
@@ -178,8 +179,30 @@
util::SecretDataFromStringView(key_or.ValueOrDie().key_value()));
ASSERT_THAT(boring_ssl_aead_or.status(), IsOk());
- ASSERT_THAT(EncryptThenDecrypt(aead_or.ValueOrDie().get(),
- boring_ssl_aead_or.ValueOrDie().get(),
+ ASSERT_THAT(EncryptThenDecrypt(*aead_or.ValueOrDie(),
+ *boring_ssl_aead_or.ValueOrDie(),
+ "message", "aad"),
+ IsOk());
+}
+
+TEST(AesGcmKeyManagerTest, CreateCordAead) {
+ AesGcmKeyFormat format;
+ format.set_key_size(32);
+ StatusOr<AesGcmKey> key_or = AesGcmKeyManager().CreateKey(format);
+ ASSERT_THAT(key_or.status(), IsOk());
+
+ StatusOr<std::unique_ptr<CordAead>> aead_or =
+ AesGcmKeyManager().GetPrimitive<CordAead>(key_or.ValueOrDie());
+
+ ASSERT_THAT(aead_or.status(), IsOk());
+
+ StatusOr<std::unique_ptr<CordAead>> boring_ssl_aead_or =
+ crypto::tink::CordAesGcmBoringSsl::New(
+ util::SecretDataFromStringView(key_or.ValueOrDie().key_value()));
+ ASSERT_THAT(boring_ssl_aead_or.status(), IsOk());
+
+ ASSERT_THAT(EncryptThenDecrypt(*aead_or.ValueOrDie(),
+ *boring_ssl_aead_or.ValueOrDie(),
"message", "aad"),
IsOk());
}
diff --git a/cc/aead/aes_gcm_siv_key_manager_test.cc b/cc/aead/aes_gcm_siv_key_manager_test.cc
index 637b8cb..9f5a5c8 100644
--- a/cc/aead/aes_gcm_siv_key_manager_test.cc
+++ b/cc/aead/aes_gcm_siv_key_manager_test.cc
@@ -167,8 +167,8 @@
util::SecretDataFromStringView(key_or.ValueOrDie().key_value()));
ASSERT_THAT(boring_ssl_aead_or.status(), IsOk());
- ASSERT_THAT(EncryptThenDecrypt(aead_or.ValueOrDie().get(),
- boring_ssl_aead_or.ValueOrDie().get(),
+ ASSERT_THAT(EncryptThenDecrypt(*aead_or.ValueOrDie().get(),
+ *boring_ssl_aead_or.ValueOrDie().get(),
"message", "aad"),
IsOk());
}
diff --git a/cc/aead/kms_aead_key_manager_test.cc b/cc/aead/kms_aead_key_manager_test.cc
index 308db71..5127ef2 100644
--- a/cc/aead/kms_aead_key_manager_test.cc
+++ b/cc/aead/kms_aead_key_manager_test.cc
@@ -123,7 +123,7 @@
DummyAead direct_aead("prefix1:some_key1");
- EXPECT_THAT(EncryptThenDecrypt(kms_aead.ValueOrDie().get(), &direct_aead,
+ EXPECT_THAT(EncryptThenDecrypt(*kms_aead.ValueOrDie(), direct_aead,
"plaintext", "aad"),
IsOk());
}
@@ -156,7 +156,7 @@
DummyAead direct_aead("prefix2:some_key2");
- EXPECT_THAT(EncryptThenDecrypt(kms_aead.ValueOrDie().get(), &direct_aead,
+ EXPECT_THAT(EncryptThenDecrypt(*kms_aead.ValueOrDie(), direct_aead,
"plaintext", "aad"),
IsOk());
}
diff --git a/cc/aead/kms_envelope_aead_key_manager_test.cc b/cc/aead/kms_envelope_aead_key_manager_test.cc
index 544d068..ff4202f 100644
--- a/cc/aead/kms_envelope_aead_key_manager_test.cc
+++ b/cc/aead/kms_envelope_aead_key_manager_test.cc
@@ -163,8 +163,8 @@
ASSERT_THAT(direct_aead.status(), IsOk());
EXPECT_THAT(
- EncryptThenDecrypt(kms_aead.ValueOrDie().get(),
- direct_aead.ValueOrDie().get(), "plaintext", "aad"),
+ EncryptThenDecrypt(*kms_aead.ValueOrDie(),
+ *direct_aead.ValueOrDie(), "plaintext", "aad"),
IsOk());
}
@@ -219,8 +219,8 @@
ASSERT_THAT(direct_aead.status(), IsOk());
EXPECT_THAT(
- EncryptThenDecrypt(kms_aead.ValueOrDie().get(),
- direct_aead.ValueOrDie().get(), "plaintext", "aad"),
+ EncryptThenDecrypt(*kms_aead.ValueOrDie(),
+ *direct_aead.ValueOrDie(), "plaintext", "aad"),
IsOk());
}
diff --git a/cc/aead/xchacha20_poly1305_key_manager_test.cc b/cc/aead/xchacha20_poly1305_key_manager_test.cc
index 3bce99a..07b1c46 100644
--- a/cc/aead/xchacha20_poly1305_key_manager_test.cc
+++ b/cc/aead/xchacha20_poly1305_key_manager_test.cc
@@ -128,8 +128,8 @@
ASSERT_THAT(direct_aead_or.status(), IsOk());
ASSERT_THAT(
- EncryptThenDecrypt(aead_or.ValueOrDie().get(),
- direct_aead_or.ValueOrDie().get(), "message", "aad"),
+ EncryptThenDecrypt(*aead_or.ValueOrDie(),
+ *direct_aead_or.ValueOrDie(), "message", "aad"),
IsOk());
}
diff --git a/cc/config/BUILD.bazel b/cc/config/BUILD.bazel
index dde6656..9c0faa3 100644
--- a/cc/config/BUILD.bazel
+++ b/cc/config/BUILD.bazel
@@ -32,6 +32,28 @@
],
)
+config_setting(
+ name = "only_fips",
+ values = {"define": "use_only_fips=on"},
+)
+
+cc_library(
+ name = "tink_fips",
+ srcs = ["tink_fips.cc"],
+ hdrs = ["tink_fips.h"],
+ include_prefix = "tink/config",
+ defines = select({
+ "only_fips": ["TINK_USE_ONLY_FIPS"],
+ "//conditions:default": [],
+ }),
+ visibility = ["//visibility:public"],
+ deps = [
+ "@com_google_absl//absl/base:core_headers",
+ "@boringssl//:crypto",
+ "//util:status",
+ ],
+)
+
# tests
cc_test(
diff --git a/cc/config/CMakeLists.txt b/cc/config/CMakeLists.txt
index e7224dc..f8ce265 100644
--- a/cc/config/CMakeLists.txt
+++ b/cc/config/CMakeLists.txt
@@ -27,6 +27,17 @@
tink::proto::config_cc_proto
)
+tink_cc_library(
+ NAME tink_fips
+ SRCS
+ tink_fips.cc
+ tink_fips.h
+ DEPS
+ absl::base
+ crypto
+ tink::util::status
+)
+
# tests
tink_cc_test(
diff --git a/cc/config/tink_fips.cc b/cc/config/tink_fips.cc
new file mode 100644
index 0000000..402f527
--- /dev/null
+++ b/cc/config/tink_fips.cc
@@ -0,0 +1,50 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "tink/config/tink_fips.h"
+
+namespace crypto {
+namespace tink {
+
+#ifdef TINK_USE_ONLY_FIPS
+const bool kUseOnlyFips = true;
+#else
+const bool kUseOnlyFips = false;
+#endif
+
+crypto::tink::util::Status ChecksFipsCompatibility(
+ FipsCompatibility fips_status) {
+ switch (fips_status) {
+ case FipsCompatibility::kNotFips:
+ if (kUseOnlyFips) {
+ return util::Status(util::error::INTERNAL,
+ "Primitive not available in FIPS only mode");
+ } else {
+ return util::OkStatus();
+ }
+ case FipsCompatibility::kRequiresBoringCrypto:
+ if (kUseOnlyFips && !FIPS_mode()) {
+ return util::Status(
+ util::error::INTERNAL,
+ "BoringSSL not built with the BoringCrypto module. If you want to "
+ "use "
+ "FIPS only mode you have to build BoringSSL in FIPS Mode.");
+
+ } else {
+ return util::OkStatus();
+ }
+ }
+}
+
+} // namespace tink
+} // namespace crypto
diff --git a/cc/config/tink_fips.h b/cc/config/tink_fips.h
new file mode 100644
index 0000000..8d1e8ed
--- /dev/null
+++ b/cc/config/tink_fips.h
@@ -0,0 +1,55 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef TINK_CONFIG_TINK_FIPS_H_
+#define TINK_CONFIG_TINK_FIPS_H_
+
+#include "absl/base/attributes.h"
+#include "openssl/crypto.h"
+#include "tink/util/status.h"
+
+namespace crypto {
+namespace tink {
+
+// This flag indicates whether Tink was build in FIPS only mode. If the flag
+// is set, then usage of algorithms will be restricted to algorithms which
+// utilize the FIPS validated BoringCrypto module.
+ABSL_CONST_INIT extern const bool kUseOnlyFips;
+
+// Should be used to indicate whether an algorithm can be used in FIPS only
+// mode or not.
+enum class FipsCompatibility {
+ kNotFips = 0, // The algorithm can not use a FIPS validated implementation.
+ kRequiresBoringCrypto, // The algorithm requires BoringCrypto to use a FIPS
+ // validated implementation.
+};
+
+// Allows to check for a cryptographic algorithm whether it is available in
+// the FIPS only mode, based on it's FipsCompatibility flag. If FIPS only
+// mode is enabled this will return an INTERNAL error if:
+// 1) The algorithm has no FIPS support.
+// 2) The algorithm has FIPS support, but BoringSSL has not been compiled with
+// the BoringCrypto module.
+crypto::tink::util::Status ChecksFipsCompatibility(
+ FipsCompatibility fips_status);
+
+// Utility function wich calls CheckFipsCompatibility(T::kFipsStatus).
+template <class T>
+crypto::tink::util::Status CheckFipsCompatibility() {
+ return ChecksFipsCompatibility(T::kFipsStatus);
+}
+
+} // namespace tink
+} // namespace crypto
+
+#endif // TINK_CONFIG_TINK_FIPS_H_
diff --git a/cc/config/tink_fips_disabled_test.cc b/cc/config/tink_fips_disabled_test.cc
new file mode 100644
index 0000000..d9877b4
--- /dev/null
+++ b/cc/config/tink_fips_disabled_test.cc
@@ -0,0 +1,48 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/config/tink_fips.h"
+#include "tink/util/test_matchers.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::test::IsOk;
+using testing::Eq;
+
+TEST(TinkFipsTest, FlagCorrectlySet) { EXPECT_THAT(kUseOnlyFips, Eq(false)); }
+
+class FipsIncompatible {
+ public:
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kNotFips;
+};
+
+class FipsCompatibleWithBoringCrypto {
+ public:
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kRequiresBoringCrypto;
+};
+
+TEST(TinkFipsTest, Compatibility) {
+ // With FIPS only mode disabled no restrictions should apply.
+ EXPECT_THAT(CheckFipsCompatibility<FipsIncompatible>(), IsOk());
+ EXPECT_THAT(CheckFipsCompatibility<FipsCompatibleWithBoringCrypto>(), IsOk());
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/cc/config/tink_fips_enabled_test.cc b/cc/config/tink_fips_enabled_test.cc
new file mode 100644
index 0000000..9562f58
--- /dev/null
+++ b/cc/config/tink_fips_enabled_test.cc
@@ -0,0 +1,81 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "openssl/crypto.h"
+#include "tink/aead.h"
+#include "tink/aead/aead_config.h"
+#include "tink/aead/aead_key_templates.h"
+#include "tink/config/tink_fips.h"
+#include "tink/keyset_handle.h"
+#include "tink/util/status.h"
+#include "tink/util/test_matchers.h"
+#include "tink/util/test_util.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::test::IsOk;
+using ::crypto::tink::test::StatusIs;
+
+TEST(TinkFipsTest, FlagCorrectlySet) {
+ EXPECT_THAT(kUseOnlyFips, testing::Eq(true));
+}
+
+class FipsIncompatible {
+ public:
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kNotFips;
+};
+
+class FipsCompatibleWithBoringCrypto {
+ public:
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kRequiresBoringCrypto;
+};
+
+TEST(TinkFipsTest, CompatibilityChecksWithBoringCrypto) {
+ if (!FIPS_mode()) {
+ GTEST_SKIP() << "Test only run if BoringCrypto module is available.";
+ }
+
+ // In FIPS only mode compatibility checks should disallow algorithms
+ // with the FipsCompatibility::kNone flag.
+ EXPECT_THAT(CheckFipsCompatibility<FipsIncompatible>(),
+ StatusIs(util::error::INTERNAL));
+
+ // FIPS validated implementations should still be allowed.
+ EXPECT_THAT(CheckFipsCompatibility<FipsCompatibleWithBoringCrypto>(), IsOk());
+}
+
+TEST(TinkFipsTest, CompatibilityChecksWithoutBoringCrypto) {
+ if (FIPS_mode()) {
+ GTEST_SKIP() << "Test only run if BoringCrypto module is not available.";
+ }
+
+ // In FIPS only mode compatibility checks should disallow algorithms
+ // with the FipsCompatibility::kNone flag.
+ EXPECT_THAT(CheckFipsCompatibility<FipsIncompatible>(),
+ StatusIs(util::error::INTERNAL));
+
+ // FIPS validated implementations are not allowed if BoringCrypto is not
+ // available.
+ EXPECT_THAT(CheckFipsCompatibility<FipsCompatibleWithBoringCrypto>(),
+ StatusIs(util::error::INTERNAL));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/cc/core/private_key_manager_impl_test.cc b/cc/core/private_key_manager_impl_test.cc
index 4f535b0..4abe0d3 100644
--- a/cc/core/private_key_manager_impl_test.cc
+++ b/cc/core/private_key_manager_impl_test.cc
@@ -70,14 +70,14 @@
return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
}
- MOCK_CONST_METHOD0(get_version, uint32_t());
+ MOCK_METHOD(uint32_t, get_version, (), (const, override));
// We mock out ValidateKey and ValidateKeyFormat so that we can easily test
// proper behavior in case they return an error.
- MOCK_CONST_METHOD1(ValidateKey,
- crypto::tink::util::Status(const EcdsaPrivateKey& key));
- MOCK_CONST_METHOD1(ValidateKeyFormat,
- crypto::tink::util::Status(const EcdsaKeyFormat& key));
+ MOCK_METHOD(crypto::tink::util::Status, ValidateKey,
+ (const EcdsaPrivateKey& key), (const, override));
+ MOCK_METHOD(crypto::tink::util::Status, ValidateKeyFormat,
+ (const EcdsaKeyFormat& key), (const, override));
const std::string& get_key_type() const override { return kKeyType; }
@@ -119,12 +119,12 @@
return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE;
}
- MOCK_CONST_METHOD0(get_version, uint32_t());
+ MOCK_METHOD(uint32_t, get_version, (), (const, override));
// We mock out ValidateKey and ValidateKeyFormat so that we can easily test
// proper behavior in case they return an error.
- MOCK_CONST_METHOD1(ValidateKey,
- crypto::tink::util::Status(const EcdsaPublicKey& key));
+ MOCK_METHOD(crypto::tink::util::Status, ValidateKey,
+ (const EcdsaPublicKey& key), (const, override));
const std::string& get_key_type() const override { return kKeyType; }
diff --git a/cc/core/registry_impl.h b/cc/core/registry_impl.h
index 58c4550..fc060e5 100644
--- a/cc/core/registry_impl.h
+++ b/cc/core/registry_impl.h
@@ -27,7 +27,6 @@
#include "absl/strings/str_join.h"
#include "absl/types/optional.h"
#include "absl/synchronization/mutex.h"
-// placeholder for dllexport_macros.h
#include "tink/catalogue.h"
#include "tink/core/key_manager_impl.h"
#include "tink/core/key_type_manager.h"
diff --git a/cc/core/registry_test.cc b/cc/core/registry_test.cc
index 4e56ae9..52ea4b7 100644
--- a/cc/core/registry_test.cc
+++ b/cc/core/registry_test.cc
@@ -1321,7 +1321,13 @@
HasSubstr("not among supported primitives")));
}
-TEST(PrivateKeyManagerImplTest, AsymmetricFactoryNewKeyFromMessage) {
+class PrivateKeyManagerImplTest : public testing::Test {
+ void SetUp() override {
+ Registry::Reset();
+ }
+};
+
+TEST_F(PrivateKeyManagerImplTest, AsymmetricFactoryNewKeyFromMessage) {
ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers(
absl::make_unique<TestPrivateKeyTypeManager>(),
absl::make_unique<TestPublicKeyTypeManager>(), true)
@@ -1343,7 +1349,7 @@
Eq(EcdsaSignatureEncoding::DER));
}
-TEST(PrivateKeyManagerImplTest, AsymmetricNewKeyDisallowed) {
+TEST_F(PrivateKeyManagerImplTest, AsymmetricNewKeyDisallowed) {
ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers(
absl::make_unique<TestPrivateKeyTypeManager>(),
absl::make_unique<TestPublicKeyTypeManager>(), true)
diff --git a/cc/daead/BUILD.bazel b/cc/daead/BUILD.bazel
index 94aceea..e29a342 100644
--- a/cc/daead/BUILD.bazel
+++ b/cc/daead/BUILD.bazel
@@ -52,6 +52,7 @@
":aes_siv_key_manager",
":deterministic_aead_wrapper",
"//config:config_util",
+ "//config:tink_fips",
"//mac:mac_config",
"//proto:config_cc_proto",
"//util:status",
@@ -140,6 +141,7 @@
"//:deterministic_aead",
"//:keyset_handle",
"//:registry",
+ "//config:tink_fips",
"//util:status",
"//util:test_matchers",
"//util:test_util",
diff --git a/cc/daead/CMakeLists.txt b/cc/daead/CMakeLists.txt
index bf04071..08b879e 100644
--- a/cc/daead/CMakeLists.txt
+++ b/cc/daead/CMakeLists.txt
@@ -47,6 +47,7 @@
tink::daead::aes_siv_key_manager
tink::daead::deterministic_aead_wrapper
tink::config::config_util
+ tink::config::tink_fips
tink::mac::mac_config
tink::util::status
tink::proto::config_cc_proto
@@ -118,6 +119,7 @@
tink::daead::aes_siv_key_manager
tink::daead::deterministic_aead_config
tink::daead::deterministic_aead_key_templates
+ tink::config::tink_fips
tink::core::config
tink::core::deterministic_aead
tink::core::keyset_handle
diff --git a/cc/daead/deterministic_aead_config.cc b/cc/daead/deterministic_aead_config.cc
index 4a4232b..f745f9d 100644
--- a/cc/daead/deterministic_aead_config.cc
+++ b/cc/daead/deterministic_aead_config.cc
@@ -18,6 +18,7 @@
#include "absl/memory/memory.h"
#include "tink/config/config_util.h"
+#include "tink/config/tink_fips.h"
#include "tink/daead/aes_siv_key_manager.h"
#include "tink/daead/deterministic_aead_wrapper.h"
#include "tink/registry.h"
@@ -37,7 +38,13 @@
// static
util::Status DeterministicAeadConfig::Register() {
- // Register key manager.
+ // Currently there are no FIPS-validated deterministic AEAD key managers
+ // available, therefore none will be registered in FIPS only mode.
+ if (kUseOnlyFips) {
+ return util::OkStatus();
+ }
+
+ // Register non-FIPS key managers.
auto status = Registry::RegisterKeyTypeManager(
absl::make_unique<AesSivKeyManager>(), true);
if (!status.ok()) return status;
diff --git a/cc/daead/deterministic_aead_config_test.cc b/cc/daead/deterministic_aead_config_test.cc
index e05cf16..6683b69 100644
--- a/cc/daead/deterministic_aead_config_test.cc
+++ b/cc/daead/deterministic_aead_config_test.cc
@@ -16,9 +16,12 @@
#include "tink/daead/deterministic_aead_config.h"
+#include <list>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "tink/config.h"
+#include "tink/config/tink_fips.h"
#include "tink/daead/aes_siv_key_manager.h"
#include "tink/daead/deterministic_aead_key_templates.h"
#include "tink/deterministic_aead.h"
@@ -43,6 +46,10 @@
};
TEST_F(DeterministicAeadConfigTest, Basic) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
EXPECT_THAT(Registry::get_key_manager<DeterministicAead>(
AesSivKeyManager().get_key_type())
.status(),
@@ -57,6 +64,10 @@
// Tests that the DeterministicAeadWrapper has been properly registered and we
// can wrap primitives.
TEST_F(DeterministicAeadConfigTest, WrappersRegistered) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
ASSERT_TRUE(DeterministicAeadConfig::Register().ok());
google::crypto::tink::Keyset::Key key;
@@ -86,10 +97,28 @@
EXPECT_THAT(decryption_result.ValueOrDie(), Eq("secret"));
decryption_result = DummyDeterministicAead("dummy").DecryptDeterministically(
- encryption_result.ValueOrDie(), "wrog");
+ encryption_result.ValueOrDie(), "wrong");
EXPECT_FALSE(decryption_result.status().ok());
}
+TEST_F(DeterministicAeadConfigTest, RegisterFipsValidTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(DeterministicAeadConfig::Register(), IsOk());
+
+ // Check that we can not retrieve non-FIPS key handle
+ std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
+ non_fips_key_templates.push_back(DeterministicAeadKeyTemplates::Aes256Siv());
+
+ for (auto key_template : non_fips_key_templates) {
+ auto new_keyset_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_THAT(new_keyset_handle_result.status(),
+ StatusIs(util::error::NOT_FOUND));
+ }
+}
+
} // namespace
} // namespace tink
} // namespace crypto
diff --git a/cc/hybrid/BUILD.bazel b/cc/hybrid/BUILD.bazel
index 55736ff..4aeac3c 100644
--- a/cc/hybrid/BUILD.bazel
+++ b/cc/hybrid/BUILD.bazel
@@ -16,6 +16,7 @@
"//:registry",
"//aead:aead_config",
"//config:config_util",
+ "//config:tink_fips",
"//proto:config_cc_proto",
"//util:status",
"@com_google_absl//absl/base:core_headers",
@@ -197,6 +198,7 @@
"//util:enums",
"//util:errors",
"//util:protobuf_helper",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:validation",
@@ -247,6 +249,7 @@
"//:hybrid_encrypt",
"//:keyset_handle",
"//:registry",
+ "//config:tink_fips",
"//util:status",
"//util:test_matchers",
"//util:test_util",
diff --git a/cc/hybrid/CMakeLists.txt b/cc/hybrid/CMakeLists.txt
index 4c7c1b4..b7a3990 100644
--- a/cc/hybrid/CMakeLists.txt
+++ b/cc/hybrid/CMakeLists.txt
@@ -12,6 +12,7 @@
tink::hybrid::hybrid_encrypt_wrapper
tink::core::registry
tink::config::config_util
+ tink::config::tink_fips
tink::aead::aead_config
tink::util::status
tink::proto::config_cc_proto
@@ -175,6 +176,7 @@
tink::util::enums
tink::util::errors
tink::util::protobuf_helper
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::validation
@@ -214,6 +216,7 @@
DEPS
tink::hybrid::hybrid_config
tink::hybrid::hybrid_key_templates
+ tink::config::tink_fips
tink::core::config
tink::core::hybrid_decrypt
tink::core::hybrid_encrypt
diff --git a/cc/hybrid/ecies_aead_hkdf_dem_helper.cc b/cc/hybrid/ecies_aead_hkdf_dem_helper.cc
index 9377cbf..fea92f1 100644
--- a/cc/hybrid/ecies_aead_hkdf_dem_helper.cc
+++ b/cc/hybrid/ecies_aead_hkdf_dem_helper.cc
@@ -105,34 +105,70 @@
if (!ReplaceKeyBytes(symmetric_key_value, key.get())) {
return util::Status(util::error::INTERNAL, "Generation of DEM-key failed.");
}
- return key_manager_->GetPrimitive(*key);
+ auto aead_or = key_manager_->GetPrimitive(*key);
+ ZeroKeyBytes(key.get());
+ return aead_or;
}
bool EciesAeadHkdfDemHelper::ReplaceKeyBytes(
const util::SecretData& key_bytes,
portable_proto::MessageLite* proto) const {
- if (key_params_.key_type == AES_GCM_KEY) {
- AesGcmKey* key = static_cast<AesGcmKey*>(proto);
- key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes)));
- return true;
- } else if (key_params_.key_type == AES_CTR_HMAC_AEAD_KEY) {
- AesCtrHmacAeadKey* key = static_cast<AesCtrHmacAeadKey*>(proto);
- auto aes_ctr_key = key->mutable_aes_ctr_key();
- aes_ctr_key->set_key_value(
- std::string(util::SecretDataAsStringView(key_bytes).substr(
- 0, key_params_.aes_ctr_key_size_in_bytes)));
- auto hmac_key = key->mutable_hmac_key();
- hmac_key->set_key_value(
- std::string(util::SecretDataAsStringView(key_bytes).substr(
- key_params_.aes_ctr_key_size_in_bytes)));
- return true;
- } else if (key_params_.key_type == XCHACHA20_POLY1305_KEY) {
- XChaCha20Poly1305Key* key = static_cast<XChaCha20Poly1305Key*>(proto);
- key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes)));
- return true;
+ switch (key_params_.key_type) {
+ case AES_GCM_KEY: {
+ AesGcmKey* key = static_cast<AesGcmKey*>(proto);
+ key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes)));
+ return true;
+ }
+ case AES_CTR_HMAC_AEAD_KEY: {
+ AesCtrHmacAeadKey* key = static_cast<AesCtrHmacAeadKey*>(proto);
+ auto aes_ctr_key = key->mutable_aes_ctr_key();
+ aes_ctr_key->set_key_value(
+ std::string(util::SecretDataAsStringView(key_bytes).substr(
+ 0, key_params_.aes_ctr_key_size_in_bytes)));
+ auto hmac_key = key->mutable_hmac_key();
+ hmac_key->set_key_value(
+ std::string(util::SecretDataAsStringView(key_bytes).substr(
+ key_params_.aes_ctr_key_size_in_bytes)));
+ return true;
+ }
+ case XCHACHA20_POLY1305_KEY: {
+ XChaCha20Poly1305Key* key = static_cast<XChaCha20Poly1305Key*>(proto);
+ key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes)));
+ return true;
+ }
}
return false;
}
+void EciesAeadHkdfDemHelper::ZeroKeyBytes(
+ portable_proto::MessageLite* proto) const {
+ switch (key_params_.key_type) {
+ case AES_GCM_KEY: {
+ AesGcmKey* key = static_cast<AesGcmKey*>(proto);
+ std::unique_ptr<std::string> key_value =
+ absl::WrapUnique(key->release_key_value());
+ util::SafeZeroString(key_value.get());
+ break;
+ }
+ case AES_CTR_HMAC_AEAD_KEY: {
+ AesCtrHmacAeadKey* key = static_cast<AesCtrHmacAeadKey*>(proto);
+ std::unique_ptr<std::string> aes_ctr_key_value =
+ absl::WrapUnique(key->mutable_aes_ctr_key()->release_key_value());
+ util::SafeZeroString(aes_ctr_key_value.get());
+ std::unique_ptr<std::string> hmac_key_value =
+ absl::WrapUnique(key->mutable_hmac_key()->release_key_value());
+ util::SafeZeroString(hmac_key_value.get());
+ break;
+ }
+ case XCHACHA20_POLY1305_KEY: {
+ XChaCha20Poly1305Key* key = static_cast<XChaCha20Poly1305Key*>(proto);
+ std::unique_ptr<std::string> key_value =
+ absl::WrapUnique(key->release_key_value());
+ util::SafeZeroString(key_value.get());
+ break;
+ }
+ }
+}
+
} // namespace tink
} // namespace crypto
diff --git a/cc/hybrid/ecies_aead_hkdf_dem_helper.h b/cc/hybrid/ecies_aead_hkdf_dem_helper.h
index de8d54b..cfb0ecb 100644
--- a/cc/hybrid/ecies_aead_hkdf_dem_helper.h
+++ b/cc/hybrid/ecies_aead_hkdf_dem_helper.h
@@ -51,7 +51,6 @@
private:
enum DemKeyType {
- UNKNOWN_KEY = 0,
AES_GCM_KEY,
AES_CTR_HMAC_AEAD_KEY,
XCHACHA20_POLY1305_KEY,
@@ -76,6 +75,8 @@
bool ReplaceKeyBytes(const util::SecretData& key_bytes,
portable_proto::MessageLite* proto) const;
+ void ZeroKeyBytes(portable_proto::MessageLite* proto) const;
+
const KeyManager<Aead>* key_manager_; // not owned
const google::crypto::tink::KeyTemplate key_template_;
const DemKeyParams key_params_;
diff --git a/cc/hybrid/ecies_aead_hkdf_hybrid_decrypt_test.cc b/cc/hybrid/ecies_aead_hkdf_hybrid_decrypt_test.cc
index 183cd30..d13883a 100644
--- a/cc/hybrid/ecies_aead_hkdf_hybrid_decrypt_test.cc
+++ b/cc/hybrid/ecies_aead_hkdf_hybrid_decrypt_test.cc
@@ -204,6 +204,7 @@
TEST_F(EciesAeadHkdfHybridDecryptTest, testGettingHybridEncryptWithoutManager) {
// Prepare an ECIES key.
+ Registry::Reset();
auto ecies_key = test::GetEciesAesGcmHkdfTestKey(
EllipticCurveType::NIST_P256,
EcPointFormat::UNCOMPRESSED,
diff --git a/cc/hybrid/ecies_aead_hkdf_private_key_manager.cc b/cc/hybrid/ecies_aead_hkdf_private_key_manager.cc
index 03b41a5..2d4ad8b 100644
--- a/cc/hybrid/ecies_aead_hkdf_private_key_manager.cc
+++ b/cc/hybrid/ecies_aead_hkdf_private_key_manager.cc
@@ -16,16 +16,17 @@
#include "tink/hybrid/ecies_aead_hkdf_private_key_manager.h"
-#include "absl/strings/string_view.h"
#include "absl/memory/memory.h"
-#include "tink/hybrid_decrypt.h"
-#include "tink/key_manager.h"
+#include "absl/strings/string_view.h"
#include "tink/hybrid/ecies_aead_hkdf_hybrid_decrypt.h"
#include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h"
+#include "tink/hybrid_decrypt.h"
+#include "tink/key_manager.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/enums.h"
#include "tink/util/errors.h"
#include "tink/util/protobuf_helper.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/validation.h"
@@ -63,7 +64,8 @@
// Build EciesAeadHkdfPrivateKey.
EciesAeadHkdfPrivateKey ecies_private_key;
ecies_private_key.set_version(get_version());
- ecies_private_key.set_key_value(ec_key.priv);
+ ecies_private_key.set_key_value(
+ std::string(util::SecretDataAsStringView(ec_key.priv)));
auto ecies_public_key = ecies_private_key.mutable_public_key();
ecies_public_key->set_version(get_version());
ecies_public_key->set_x(ec_key.pub_x);
diff --git a/cc/hybrid/hybrid_config.cc b/cc/hybrid/hybrid_config.cc
index 4f44d8b..3176fd1 100644
--- a/cc/hybrid/hybrid_config.cc
+++ b/cc/hybrid/hybrid_config.cc
@@ -21,6 +21,7 @@
#include "tink/hybrid/ecies_aead_hkdf_private_key_manager.h"
#include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h"
#include "tink/config/config_util.h"
+#include "tink/config/tink_fips.h"
#include "tink/registry.h"
#include "tink/hybrid/hybrid_decrypt_wrapper.h"
#include "tink/hybrid/hybrid_encrypt_wrapper.h"
@@ -42,19 +43,29 @@
util::Status HybridConfig::Register() {
auto status = AeadConfig::Register();
- // Register key managers.
+ // Register primitive wrappers.
+ status = Registry::RegisterPrimitiveWrapper(
+ absl::make_unique<HybridEncryptWrapper>());
+ if (!status.ok()) return status;
+ status = Registry::RegisterPrimitiveWrapper(
+ absl::make_unique<HybridDecryptWrapper>());
+ if (!status.ok()) return status;
+
+ // Currently there are no hybrid encryption key managers which only use
+ // FIPS-validated implementations, therefore none will be registered in
+ // FIPS only mode.
+ if (kUseOnlyFips) {
+ return util::OkStatus();
+ }
+
+ // Register non-FIPS key managers.
if (!status.ok()) return status;
status = Registry::RegisterAsymmetricKeyManagers(
absl::make_unique<EciesAeadHkdfPrivateKeyManager>(),
absl::make_unique<EciesAeadHkdfPublicKeyManager>(), true);
if (!status.ok()) return status;
- // Register primitive wrappers.
- status = Registry::RegisterPrimitiveWrapper(
- absl::make_unique<HybridEncryptWrapper>());
- if (!status.ok()) return status;
- return Registry::RegisterPrimitiveWrapper(
- absl::make_unique<HybridDecryptWrapper>());
+ return util::OkStatus();
}
} // namespace tink
diff --git a/cc/hybrid/hybrid_config_test.cc b/cc/hybrid/hybrid_config_test.cc
index 2479bad..fe72668 100644
--- a/cc/hybrid/hybrid_config_test.cc
+++ b/cc/hybrid/hybrid_config_test.cc
@@ -16,9 +16,12 @@
#include "tink/hybrid/hybrid_config.h"
+#include <list>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "tink/config.h"
+#include "tink/config/tink_fips.h"
#include "tink/hybrid/ecies_aead_hkdf_private_key_manager.h"
#include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h"
#include "tink/hybrid/hybrid_key_templates.h"
@@ -45,6 +48,10 @@
};
TEST_F(HybridConfigTest, Basic) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
EXPECT_THAT(Registry::get_key_manager<HybridDecrypt>(
EciesAeadHkdfPrivateKeyManager().get_key_type())
.status(),
@@ -67,6 +74,10 @@
// Tests that the HybridEncryptWrapper has been properly registered and we
// can wrap primitives.
TEST_F(HybridConfigTest, EncryptWrapperRegistered) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
ASSERT_TRUE(HybridConfig::Register().ok());
google::crypto::tink::Keyset::Key key;
@@ -98,6 +109,10 @@
// Tests that the HybridDecryptWrapper has been properly registered and we
// can wrap primitives.
TEST_F(HybridConfigTest, DecryptWrapperRegistered) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
ASSERT_TRUE(HybridConfig::Register().ok());
google::crypto::tink::Keyset::Key key;
@@ -126,6 +141,41 @@
"secret");
}
+// FIPS-only mode tests
+TEST_F(HybridConfigTest, RegisterNonFipsTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(HybridConfig::Register(), IsOk());
+
+ // Check that we can not retrieve non-FIPS keyset handle
+ std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::
+ EciesP256CompressedHkdfHmacSha256Aes128CtrHmacSha256());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesP256CompressedHkdfHmacSha256Aes128Gcm());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128CtrHmacSha256());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::
+ EciesP256HkdfHmacSha256Aes128GcmCompressedWithoutPrefix());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesX25519HkdfHmacSha256Aes128CtrHmacSha256());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesX25519HkdfHmacSha256Aes128Gcm());
+ non_fips_key_templates.push_back(
+ HybridKeyTemplates::EciesX25519HkdfHmacSha256XChaCha20Poly1305());
+
+ for (auto key_template : non_fips_key_templates) {
+ EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(),
+ StatusIs(util::error::NOT_FOUND));
+ }
+}
+
} // namespace
} // namespace tink
} // namespace crypto
diff --git a/cc/integration/gcpkms/gcp_kms_aead.cc b/cc/integration/gcpkms/gcp_kms_aead.cc
index be752c6..620cac6 100644
--- a/cc/integration/gcpkms/gcp_kms_aead.cc
+++ b/cc/integration/gcpkms/gcp_kms_aead.cc
@@ -67,6 +67,9 @@
EncryptResponse resp;
ClientContext context;
+ context.AddMetadata("x-goog-request-params",
+ absl::StrCat("name=", key_name_));
+
auto status = kms_stub_->Encrypt(&context, req, &resp);
if (status.ok()) return resp.ciphertext();
@@ -83,6 +86,9 @@
DecryptResponse resp;
ClientContext context;
+ context.AddMetadata("x-goog-request-params",
+ absl::StrCat("name=", key_name_));
+
auto status = kms_stub_->Decrypt(&context, req, &resp);
if (status.ok()) return resp.plaintext();
diff --git a/cc/integration/gcpkms/gcp_kms_aead_test.cc b/cc/integration/gcpkms/gcp_kms_aead_test.cc
index 846064d..0d1251a 100644
--- a/cc/integration/gcpkms/gcp_kms_aead_test.cc
+++ b/cc/integration/gcpkms/gcp_kms_aead_test.cc
@@ -23,7 +23,8 @@
using crypto::tink::integration::gcpkms::GcpKmsAead;
class GcpKmsAeadTest : public ::testing::Test {
- // TODO(przydatek): add a test with a mock KMSClient.
+ // TODO(kste): Add tests when mock for
+ // google::cloud::kms::v1::KeyManagementService::StubInterface is available.
};
diff --git a/cc/mac/BUILD.bazel b/cc/mac/BUILD.bazel
index 7491832..960a7f3 100644
--- a/cc/mac/BUILD.bazel
+++ b/cc/mac/BUILD.bazel
@@ -31,6 +31,7 @@
":mac_wrapper",
"//:registry",
"//config:config_util",
+ "//config:tink_fips",
"//proto:config_cc_proto",
"//util:status",
"@com_google_absl//absl/base:core_headers",
@@ -156,6 +157,7 @@
"//:keyset_handle",
"//:mac",
"//:registry",
+ "//config:tink_fips",
"//util:status",
"//util:test_matchers",
"//util:test_util",
diff --git a/cc/mac/CMakeLists.txt b/cc/mac/CMakeLists.txt
index 89fdfbb..b79e398 100644
--- a/cc/mac/CMakeLists.txt
+++ b/cc/mac/CMakeLists.txt
@@ -26,6 +26,7 @@
tink::mac::hmac_key_manager
tink::mac::mac_wrapper
tink::config::config_util
+ tink::config::tink_fips
tink::core::registry
tink::util::status
tink::proto::config_cc_proto
@@ -136,6 +137,7 @@
tink::mac::hmac_key_manager
tink::mac::mac_config
tink::mac::mac_key_templates
+ tink::config::tink_fips
tink::core::config
tink::core::keyset_handle
tink::core::mac
diff --git a/cc/mac/mac_config.cc b/cc/mac/mac_config.cc
index b891285..99d9110 100644
--- a/cc/mac/mac_config.cc
+++ b/cc/mac/mac_config.cc
@@ -18,6 +18,7 @@
#include "absl/memory/memory.h"
#include "tink/config/config_util.h"
+#include "tink/config/tink_fips.h"
#include "tink/mac/aes_cmac_key_manager.h"
#include "tink/mac/hmac_key_manager.h"
#include "tink/mac/mac_wrapper.h"
@@ -38,16 +39,27 @@
// static
util::Status MacConfig::Register() {
- // Register key managers.
- auto status = Registry::RegisterKeyTypeManager(
- absl::make_unique<HmacKeyManager>(), true);
+ // Register primitive wrapper.
+ auto status =
+ Registry::RegisterPrimitiveWrapper(absl::make_unique<MacWrapper>());
if (!status.ok()) return status;
+
+ // Register key managers which utilize the FIPS validated BoringCrypto
+ // implementations.
+ status = Registry::RegisterKeyTypeManager(absl::make_unique<HmacKeyManager>(),
+ true);
+ if (!status.ok()) return status;
+
+ if (kUseOnlyFips) {
+ return util::OkStatus();
+ }
+
+ // CMac in BoringSSL is not FIPS validated.
status = Registry::RegisterKeyTypeManager(
absl::make_unique<AesCmacKeyManager>(), true);
if (!status.ok()) return status;
- // Register primitive wrapper.
- return Registry::RegisterPrimitiveWrapper(absl::make_unique<MacWrapper>());
+ return util::OkStatus();
}
} // namespace tink
diff --git a/cc/mac/mac_config_test.cc b/cc/mac/mac_config_test.cc
index a6208e6..f4048ce 100644
--- a/cc/mac/mac_config_test.cc
+++ b/cc/mac/mac_config_test.cc
@@ -16,8 +16,11 @@
#include "tink/mac/mac_config.h"
+#include <list>
+
#include "gtest/gtest.h"
#include "tink/config.h"
+#include "tink/config/tink_fips.h"
#include "tink/keyset_handle.h"
#include "tink/mac.h"
#include "tink/mac/hmac_key_manager.h"
@@ -84,6 +87,41 @@
DummyMac("dummy").VerifyMac(mac_result.ValueOrDie(), "faked text").ok());
}
+// FIPS-only mode tests
+TEST_F(MacConfigTest, RegisterNonFipsTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(MacConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
+ non_fips_key_templates.push_back(MacKeyTemplates::AesCmac());
+
+ for (auto key_template : non_fips_key_templates) {
+ EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(),
+ StatusIs(util::error::NOT_FOUND));
+ }
+}
+
+TEST_F(MacConfigTest, RegisterFipsValidTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(MacConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> fips_key_templates;
+ fips_key_templates.push_back(MacKeyTemplates::HmacSha256());
+ fips_key_templates.push_back(MacKeyTemplates::HmacSha256HalfSizeTag());
+ fips_key_templates.push_back(MacKeyTemplates::HmacSha512());
+ fips_key_templates.push_back(MacKeyTemplates::HmacSha512HalfSizeTag());
+
+ for (auto key_template : fips_key_templates) {
+ EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(), IsOk());
+ }
+}
+
} // namespace
} // namespace tink
} // namespace crypto
diff --git a/cc/signature/BUILD.bazel b/cc/signature/BUILD.bazel
index 4ecf857..5748a6b 100644
--- a/cc/signature/BUILD.bazel
+++ b/cc/signature/BUILD.bazel
@@ -111,6 +111,7 @@
"//util:enums",
"//util:errors",
"//util:protobuf_helper",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:validation",
@@ -219,6 +220,7 @@
"//util:enums",
"//util:errors",
"//util:protobuf_helper",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"@com_google_absl//absl/memory",
@@ -270,6 +272,7 @@
"//util:enums",
"//util:errors",
"//util:protobuf_helper",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"@com_google_absl//absl/memory",
@@ -296,6 +299,7 @@
"//util:enums",
"//util:errors",
"//util:protobuf_helper",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"@com_google_absl//absl/memory",
@@ -322,6 +326,7 @@
":rsa_ssa_pss_verify_key_manager",
"//:registry",
"//config:config_util",
+ "//config:tink_fips",
"//proto:config_cc_proto",
"//util:status",
"@com_google_absl//absl/base:core_headers",
@@ -348,6 +353,7 @@
"//subtle:subtle_util_boringssl",
"//util:enums",
"//util:keyset_util",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"@com_google_absl//absl/memory",
@@ -456,6 +462,7 @@
"//subtle:ecdsa_sign_boringssl",
"//subtle:subtle_util_boringssl",
"//util:enums",
+ "//util:secret_data",
"//util:status",
"//util:test_matchers",
"//util:test_util",
@@ -500,6 +507,7 @@
"//proto:tink_cc_proto",
"//subtle:rsa_ssa_pkcs1_sign_boringssl",
"//subtle:subtle_util_boringssl",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
@@ -523,6 +531,7 @@
"//proto:rsa_ssa_pss_cc_proto",
"//subtle:rsa_ssa_pss_sign_boringssl",
"//subtle:subtle_util_boringssl",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
@@ -590,6 +599,7 @@
"//proto:tink_cc_proto",
"//subtle:rsa_ssa_pkcs1_verify_boringssl",
"//subtle:subtle_util_boringssl",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
@@ -614,6 +624,7 @@
"//proto:rsa_ssa_pss_cc_proto",
"//subtle:rsa_ssa_pss_verify_boringssl",
"//subtle:subtle_util_boringssl",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
@@ -639,6 +650,7 @@
"//:public_key_sign",
"//:public_key_verify",
"//:registry",
+ "//config:tink_fips",
"//util:status",
"//util:test_matchers",
"//util:test_util",
@@ -689,6 +701,7 @@
"//subtle:subtle_util_boringssl",
"//util:enums",
"//util:keyset_util",
+ "//util:secret_data",
"//util:status",
"//util:test_matchers",
"@com_google_absl//absl/memory",
diff --git a/cc/signature/CMakeLists.txt b/cc/signature/CMakeLists.txt
index 3aa62f2..85611e9 100644
--- a/cc/signature/CMakeLists.txt
+++ b/cc/signature/CMakeLists.txt
@@ -102,6 +102,7 @@
tink::util::enums
tink::util::errors
tink::util::protobuf_helper
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::proto::ecdsa_cc_proto
@@ -203,6 +204,7 @@
tink::util::enums
tink::util::errors
tink::util::protobuf_helper
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::validation
@@ -250,6 +252,7 @@
tink::util::enums
tink::util::errors
tink::util::protobuf_helper
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::proto::common_cc_proto
@@ -274,6 +277,7 @@
tink::util::enums
tink::util::errors
tink::util::protobuf_helper
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::proto::common_cc_proto
@@ -300,6 +304,7 @@
tink::signature::public_key_sign_wrapper
tink::signature::public_key_verify_wrapper
tink::config::config_util
+ tink::config::tink_fips
tink::core::registry
tink::util::status
tink::proto::config_cc_proto
@@ -321,6 +326,7 @@
tink::subtle::subtle_util_boringssl
tink::util::enums
tink::util::keyset_util
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::proto::common_cc_proto
@@ -409,6 +415,7 @@
tink::subtle::ecdsa_sign_boringssl
tink::subtle::subtle_util_boringssl
tink::util::enums
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_matchers
@@ -445,6 +452,7 @@
tink::signature::rsa_ssa_pkcs1_verify_key_manager
tink::core::public_key_sign
tink::core::public_key_verify
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_util
@@ -464,6 +472,7 @@
tink::signature::rsa_ssa_pss_verify_key_manager
tink::core::public_key_sign
tink::core::public_key_verify
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_util
@@ -524,6 +533,7 @@
tink::core::public_key_verify
tink::subtle::rsa_ssa_pkcs1_verify_boringssl
tink::subtle::subtle_util_boringssl
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_matchers
@@ -545,6 +555,7 @@
tink::core::public_key_sign
tink::subtle::rsa_ssa_pss_verify_boringssl
tink::subtle::subtle_util_boringssl
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_matchers
@@ -563,6 +574,7 @@
tink::signature::rsa_ssa_pss_verify_key_manager
tink::signature::signature_config
tink::signature::signature_key_templates
+ tink::config::tink_fips
tink::core::config
tink::core::keyset_handle
tink::core::public_key_sign
@@ -606,6 +618,7 @@
tink::subtle::subtle_util_boringssl
tink::util::enums
tink::util::keyset_util
+ tink::util::secret_data
tink::util::status
tink::util::test_util
tink::proto::common_cc_proto
diff --git a/cc/signature/ecdsa_sign_key_manager.cc b/cc/signature/ecdsa_sign_key_manager.cc
index 3449e4e..2adaaf2 100644
--- a/cc/signature/ecdsa_sign_key_manager.cc
+++ b/cc/signature/ecdsa_sign_key_manager.cc
@@ -25,6 +25,7 @@
#include "tink/util/enums.h"
#include "tink/util/errors.h"
#include "tink/util/protobuf_helper.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/validation.h"
@@ -51,7 +52,8 @@
// Build EcdsaPrivateKey.
EcdsaPrivateKey ecdsa_private_key;
ecdsa_private_key.set_version(get_version());
- ecdsa_private_key.set_key_value(ec_key.priv);
+ ecdsa_private_key.set_key_value(
+ std::string(util::SecretDataAsStringView(ec_key.priv)));
auto ecdsa_public_key = ecdsa_private_key.mutable_public_key();
ecdsa_public_key->set_version(get_version());
ecdsa_public_key->set_x(ec_key.pub_x);
@@ -68,7 +70,7 @@
ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve());
ec_key.pub_x = public_key.x();
ec_key.pub_y = public_key.y();
- ec_key.priv = ecdsa_private_key.key_value();
+ ec_key.priv = util::SecretDataFromStringView(ecdsa_private_key.key_value());
auto result = subtle::EcdsaSignBoringSsl::New(
ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()),
Enums::ProtoToSubtle(public_key.params().encoding()));
diff --git a/cc/signature/ecdsa_verify_key_manager_test.cc b/cc/signature/ecdsa_verify_key_manager_test.cc
index 5fa27e6..030816e 100644
--- a/cc/signature/ecdsa_verify_key_manager_test.cc
+++ b/cc/signature/ecdsa_verify_key_manager_test.cc
@@ -24,6 +24,7 @@
#include "tink/subtle/ecdsa_sign_boringssl.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/enums.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
@@ -167,7 +168,7 @@
ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve());
ec_key.pub_x = public_key.x();
ec_key.pub_y = public_key.y();
- ec_key.priv = private_key.key_value();
+ ec_key.priv = util::SecretDataFromStringView(private_key.key_value());
auto direct_signer_or = subtle::EcdsaSignBoringSsl::New(
ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()),
@@ -195,7 +196,7 @@
ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve());
ec_key.pub_x = public_key.x();
ec_key.pub_y = public_key.y();
- ec_key.priv = private_key.key_value();
+ ec_key.priv = util::SecretDataFromStringView(private_key.key_value());
auto direct_signer_or = subtle::EcdsaSignBoringSsl::New(
ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()),
diff --git a/cc/signature/rsa_ssa_pkcs1_sign_key_manager.cc b/cc/signature/rsa_ssa_pkcs1_sign_key_manager.cc
index b7a791b..9ecae29 100644
--- a/cc/signature/rsa_ssa_pkcs1_sign_key_manager.cc
+++ b/cc/signature/rsa_ssa_pkcs1_sign_key_manager.cc
@@ -27,6 +27,7 @@
#include "tink/util/enums.h"
#include "tink/util/errors.h"
#include "tink/util/protobuf_helper.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/validation.h"
@@ -47,12 +48,12 @@
const subtle::SubtleUtilBoringSSL::RsaPrivateKey& private_key) {
RsaSsaPkcs1PrivateKey key_proto;
key_proto.set_version(RsaSsaPkcs1SignKeyManager().get_version());
- key_proto.set_d(private_key.d);
- key_proto.set_p(private_key.p);
- key_proto.set_q(private_key.q);
- key_proto.set_dp(private_key.dp);
- key_proto.set_dq(private_key.dq);
- key_proto.set_crt(private_key.crt);
+ key_proto.set_d(std::string(util::SecretDataAsStringView(private_key.d)));
+ key_proto.set_p(std::string(util::SecretDataAsStringView(private_key.p)));
+ key_proto.set_q(std::string(util::SecretDataAsStringView(private_key.q)));
+ key_proto.set_dp(std::string(util::SecretDataAsStringView(private_key.dp)));
+ key_proto.set_dq(std::string(util::SecretDataAsStringView(private_key.dq)));
+ key_proto.set_crt(std::string(util::SecretDataAsStringView(private_key.crt)));
auto* public_key_proto = key_proto.mutable_public_key();
public_key_proto->set_version(RsaSsaPkcs1SignKeyManager().get_version());
public_key_proto->set_n(private_key.n);
@@ -65,12 +66,12 @@
subtle::SubtleUtilBoringSSL::RsaPrivateKey key;
key.n = key_proto.public_key().n();
key.e = key_proto.public_key().e();
- key.d = key_proto.d();
- key.p = key_proto.p();
- key.q = key_proto.q();
- key.dp = key_proto.dp();
- key.dq = key_proto.dq();
- key.crt = key_proto.crt();
+ key.d = util::SecretDataFromStringView(key_proto.d());
+ key.p = util::SecretDataFromStringView(key_proto.p());
+ key.q = util::SecretDataFromStringView(key_proto.q());
+ key.dp = util::SecretDataFromStringView(key_proto.dp());
+ key.dq = util::SecretDataFromStringView(key_proto.dq());
+ key.crt = util::SecretDataFromStringView(key_proto.crt());
return key;
}
diff --git a/cc/signature/rsa_ssa_pkcs1_verify_key_manager_test.cc b/cc/signature/rsa_ssa_pkcs1_verify_key_manager_test.cc
index 93e54fd..d6d5739 100644
--- a/cc/signature/rsa_ssa_pkcs1_verify_key_manager_test.cc
+++ b/cc/signature/rsa_ssa_pkcs1_verify_key_manager_test.cc
@@ -26,6 +26,7 @@
#include "tink/signature/rsa_ssa_pkcs1_sign_key_manager.h"
#include "tink/subtle/rsa_ssa_pkcs1_sign_boringssl.h"
#include "tink/subtle/subtle_util_boringssl.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
@@ -133,12 +134,12 @@
subtle::SubtleUtilBoringSSL::RsaPrivateKey private_key_subtle;
private_key_subtle.n = private_key.public_key().n();
private_key_subtle.e = private_key.public_key().e();
- private_key_subtle.d = private_key.d();
- private_key_subtle.p = private_key.p();
- private_key_subtle.q = private_key.q();
- private_key_subtle.dp = private_key.dp();
- private_key_subtle.dq = private_key.dq();
- private_key_subtle.crt = private_key.crt();
+ private_key_subtle.d = util::SecretDataFromStringView(private_key.d());
+ private_key_subtle.p = util::SecretDataFromStringView(private_key.p());
+ private_key_subtle.q = util::SecretDataFromStringView(private_key.q());
+ private_key_subtle.dp = util::SecretDataFromStringView(private_key.dp());
+ private_key_subtle.dq = util::SecretDataFromStringView(private_key.dq());
+ private_key_subtle.crt = util::SecretDataFromStringView(private_key.crt());
auto direct_signer_or = subtle::RsaSsaPkcs1SignBoringSsl::New(
private_key_subtle, {crypto::tink::subtle::HashType::SHA256});
diff --git a/cc/signature/rsa_ssa_pss_sign_key_manager.cc b/cc/signature/rsa_ssa_pss_sign_key_manager.cc
index 5f0ccba..e8b947b 100644
--- a/cc/signature/rsa_ssa_pss_sign_key_manager.cc
+++ b/cc/signature/rsa_ssa_pss_sign_key_manager.cc
@@ -26,6 +26,7 @@
#include "tink/util/enums.h"
#include "tink/util/errors.h"
#include "tink/util/protobuf_helper.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/validation.h"
@@ -47,12 +48,13 @@
const subtle::SubtleUtilBoringSSL::RsaPrivateKey& private_key) {
auto key_proto = absl::make_unique<RsaSsaPssPrivateKey>();
key_proto->set_version(RsaSsaPssSignKeyManager().get_version());
- key_proto->set_d(private_key.d);
- key_proto->set_p(private_key.p);
- key_proto->set_q(private_key.q);
- key_proto->set_dp(private_key.dp);
- key_proto->set_dq(private_key.dq);
- key_proto->set_crt(private_key.crt);
+ key_proto->set_d(std::string(util::SecretDataAsStringView(private_key.d)));
+ key_proto->set_p(std::string(util::SecretDataAsStringView(private_key.p)));
+ key_proto->set_q(std::string(util::SecretDataAsStringView(private_key.q)));
+ key_proto->set_dp(std::string(util::SecretDataAsStringView(private_key.dp)));
+ key_proto->set_dq(std::string(util::SecretDataAsStringView(private_key.dq)));
+ key_proto->set_crt(
+ std::string(util::SecretDataAsStringView(private_key.crt)));
auto* public_key_proto = key_proto->mutable_public_key();
public_key_proto->set_version(RsaSsaPssSignKeyManager().get_version());
public_key_proto->set_n(private_key.n);
@@ -65,12 +67,12 @@
subtle::SubtleUtilBoringSSL::RsaPrivateKey key;
key.n = key_proto.public_key().n();
key.e = key_proto.public_key().e();
- key.d = key_proto.d();
- key.p = key_proto.p();
- key.q = key_proto.q();
- key.dp = key_proto.dp();
- key.dq = key_proto.dq();
- key.crt = key_proto.crt();
+ key.d = util::SecretDataFromStringView(key_proto.d());
+ key.p = util::SecretDataFromStringView(key_proto.p());
+ key.q = util::SecretDataFromStringView(key_proto.q());
+ key.dp = util::SecretDataFromStringView(key_proto.dp());
+ key.dq = util::SecretDataFromStringView(key_proto.dq());
+ key.crt = util::SecretDataFromStringView(key_proto.crt());
return key;
}
diff --git a/cc/signature/rsa_ssa_pss_verify_key_manager.cc b/cc/signature/rsa_ssa_pss_verify_key_manager.cc
index 92245e8..e3461e4 100644
--- a/cc/signature/rsa_ssa_pss_verify_key_manager.cc
+++ b/cc/signature/rsa_ssa_pss_verify_key_manager.cc
@@ -30,7 +30,7 @@
#include "proto/tink.pb.h"
// TODO(quannguyen):
-// + Validate salt length and possible e.
+// + Validate possible e.
namespace crypto {
namespace tink {
@@ -92,6 +92,10 @@
"MGF1 hash '%d' is different from signature hash '%d'",
params.mgf1_hash(), params.sig_hash());
}
+ if (params.salt_length() < 0) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "salt length is negative");
+ }
return Status::OK;
}
diff --git a/cc/signature/rsa_ssa_pss_verify_key_manager_test.cc b/cc/signature/rsa_ssa_pss_verify_key_manager_test.cc
index a8fa3a9..fb5c572 100644
--- a/cc/signature/rsa_ssa_pss_verify_key_manager_test.cc
+++ b/cc/signature/rsa_ssa_pss_verify_key_manager_test.cc
@@ -25,6 +25,7 @@
#include "tink/signature/rsa_ssa_pss_sign_key_manager.h"
#include "tink/subtle/rsa_ssa_pss_sign_boringssl.h"
#include "tink/subtle/subtle_util_boringssl.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
@@ -135,6 +136,12 @@
HasSubstr("only modulus size >= 2048")));
}
+TEST(RsaSsaPssVerifyKeyManagerTest, NegativeSaltLengthFails) {
+ RsaSsaPssPublicKey key = CreateValidPublicKey();
+ key.mutable_params()->set_salt_length(-5);
+ EXPECT_THAT(RsaSsaPssVerifyKeyManager().ValidateKey(key), Not(IsOk()));
+}
+
TEST(RsaSsaPssSignKeyManagerTest, Create) {
RsaSsaPssKeyFormat key_format =
CreateKeyFormat(HashType::SHA256, HashType::SHA256, 32, 3072, RSA_F4);
@@ -148,12 +155,12 @@
subtle::SubtleUtilBoringSSL::RsaPrivateKey private_key_subtle;
private_key_subtle.n = private_key.public_key().n();
private_key_subtle.e = private_key.public_key().e();
- private_key_subtle.d = private_key.d();
- private_key_subtle.p = private_key.p();
- private_key_subtle.q = private_key.q();
- private_key_subtle.dp = private_key.dp();
- private_key_subtle.dq = private_key.dq();
- private_key_subtle.crt = private_key.crt();
+ private_key_subtle.d = util::SecretDataFromStringView(private_key.d());
+ private_key_subtle.p = util::SecretDataFromStringView(private_key.p());
+ private_key_subtle.q = util::SecretDataFromStringView(private_key.q());
+ private_key_subtle.dp = util::SecretDataFromStringView(private_key.dp());
+ private_key_subtle.dq = util::SecretDataFromStringView(private_key.dq());
+ private_key_subtle.crt = util::SecretDataFromStringView(private_key.crt());
auto direct_signer_or = subtle::RsaSsaPssSignBoringSsl::New(
private_key_subtle, {crypto::tink::subtle::HashType::SHA256,
diff --git a/cc/signature/signature_config.cc b/cc/signature/signature_config.cc
index 75f463d..b5e6e75 100644
--- a/cc/signature/signature_config.cc
+++ b/cc/signature/signature_config.cc
@@ -18,6 +18,7 @@
#include "absl/memory/memory.h"
#include "tink/config/config_util.h"
+#include "tink/config/tink_fips.h"
#include "tink/registry.h"
#include "tink/signature/ecdsa_sign_key_manager.h"
#include "tink/signature/ed25519_sign_key_manager.h"
@@ -45,17 +46,20 @@
// static
util::Status SignatureConfig::Register() {
- // Register key managers.
- // ECDSA
- auto status = Registry::RegisterAsymmetricKeyManagers(
- absl::make_unique<EcdsaSignKeyManager>(),
- absl::make_unique<EcdsaVerifyKeyManager>(), true);
+ // Register primitive wrappers.
+ auto status = Registry::RegisterPrimitiveWrapper(
+ absl::make_unique<PublicKeySignWrapper>());
+ if (!status.ok()) return status;
+ status = Registry::RegisterPrimitiveWrapper(
+ absl::make_unique<PublicKeyVerifyWrapper>());
if (!status.ok()) return status;
- // ED25519
+ // Register key managers which utilize FIPS validated BoringCrypto
+ // implementations.
+ // ECDSA
status = Registry::RegisterAsymmetricKeyManagers(
- absl::make_unique<Ed25519SignKeyManager>(),
- absl::make_unique<Ed25519VerifyKeyManager>(), true);
+ absl::make_unique<EcdsaSignKeyManager>(),
+ absl::make_unique<EcdsaVerifyKeyManager>(), true);
if (!status.ok()) return status;
// RSA SSA PSS
@@ -70,12 +74,17 @@
absl::make_unique<RsaSsaPkcs1VerifyKeyManager>(), true);
if (!status.ok()) return status;
- // Register primitive wrappers.
- status = Registry::RegisterPrimitiveWrapper(
- absl::make_unique<PublicKeySignWrapper>());
+ if (kUseOnlyFips) {
+ return util::OkStatus();
+ }
+
+ // ED25519
+ status = Registry::RegisterAsymmetricKeyManagers(
+ absl::make_unique<Ed25519SignKeyManager>(),
+ absl::make_unique<Ed25519VerifyKeyManager>(), true);
if (!status.ok()) return status;
- return Registry::RegisterPrimitiveWrapper(
- absl::make_unique<PublicKeyVerifyWrapper>());
+
+ return util::OkStatus();
}
} // namespace tink
diff --git a/cc/signature/signature_config_test.cc b/cc/signature/signature_config_test.cc
index 46f2f90..f1bf2ab 100644
--- a/cc/signature/signature_config_test.cc
+++ b/cc/signature/signature_config_test.cc
@@ -16,10 +16,13 @@
#include "tink/signature/signature_config.h"
+#include <list>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "tink/config.h"
+#include "tink/config/tink_fips.h"
#include "tink/keyset_handle.h"
#include "tink/public_key_sign.h"
#include "tink/public_key_verify.h"
@@ -39,6 +42,7 @@
using ::crypto::tink::test::DummyPublicKeyVerify;
using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::StatusIs;
+using ::testing::Not;
class SignatureConfigTest : public ::testing::Test {
protected:
@@ -122,6 +126,56 @@
.ok());
}
+// FIPS-only mode tests
+TEST_F(SignatureConfigTest, RegisterNonFipsTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(SignatureConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> non_fips_key_templates;
+ non_fips_key_templates.push_back(SignatureKeyTemplates::Ed25519());
+ non_fips_key_templates.push_back(
+ SignatureKeyTemplates::Ed25519WithRawOutput());
+ // 4096-bit RSA is not validated.
+ non_fips_key_templates.push_back(
+ SignatureKeyTemplates::RsaSsaPkcs14096Sha512F4());
+ non_fips_key_templates.push_back(
+ SignatureKeyTemplates::RsaSsaPss4096Sha384Sha384F4());
+ non_fips_key_templates.push_back(
+ SignatureKeyTemplates::RsaSsaPss4096Sha512Sha512F4());
+
+ for (auto key_template : non_fips_key_templates) {
+ EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(),
+ Not(IsOk()));
+ }
+}
+
+TEST_F(SignatureConfigTest, RegisterFipsValidTemplates) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ EXPECT_THAT(SignatureConfig::Register(), IsOk());
+
+ std::list<google::crypto::tink::KeyTemplate> fips_key_templates;
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP256());
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP256Ieee());
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP384());
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP384Ieee());
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP521());
+ fips_key_templates.push_back(SignatureKeyTemplates::EcdsaP521Ieee());
+ fips_key_templates.push_back(
+ SignatureKeyTemplates::RsaSsaPkcs13072Sha256F4());
+ fips_key_templates.push_back(
+ SignatureKeyTemplates::RsaSsaPss3072Sha256Sha256F4());
+
+ for (auto key_template : fips_key_templates) {
+ EXPECT_THAT(KeysetHandle::GenerateNew(key_template).status(), IsOk());
+ }
+}
+
} // namespace
} // namespace tink
} // namespace crypto
diff --git a/cc/signature/signature_pem_keyset_reader.cc b/cc/signature/signature_pem_keyset_reader.cc
index df4f305..da05524 100644
--- a/cc/signature/signature_pem_keyset_reader.cc
+++ b/cc/signature/signature_pem_keyset_reader.cc
@@ -32,6 +32,7 @@
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/enums.h"
#include "tink/util/keyset_util.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "proto/common.pb.h"
@@ -101,12 +102,18 @@
// RSA Private key parameters.
private_key_proto.set_version(key_version);
- private_key_proto.set_d(private_key_subtle.d);
- private_key_proto.set_p(private_key_subtle.p);
- private_key_proto.set_q(private_key_subtle.q);
- private_key_proto.set_dp(private_key_subtle.dp);
- private_key_proto.set_dq(private_key_subtle.dq);
- private_key_proto.set_crt(private_key_subtle.crt);
+ private_key_proto.set_d(
+ std::string(util::SecretDataAsStringView(private_key_subtle.d)));
+ private_key_proto.set_p(
+ std::string(util::SecretDataAsStringView(private_key_subtle.p)));
+ private_key_proto.set_q(
+ std::string(util::SecretDataAsStringView(private_key_subtle.q)));
+ private_key_proto.set_dp(
+ std::string(util::SecretDataAsStringView(private_key_subtle.dp)));
+ private_key_proto.set_dq(
+ std::string(util::SecretDataAsStringView(private_key_subtle.dq)));
+ private_key_proto.set_crt(
+ std::string(util::SecretDataAsStringView(private_key_subtle.crt)));
// Inner RSA public key.
RsaSsaPssPublicKey* public_key_proto = private_key_proto.mutable_public_key();
@@ -134,12 +141,18 @@
// RSA Private key parameters.
private_key_proto.set_version(key_version);
- private_key_proto.set_d(private_key_subtle.d);
- private_key_proto.set_p(private_key_subtle.p);
- private_key_proto.set_q(private_key_subtle.q);
- private_key_proto.set_dp(private_key_subtle.dp);
- private_key_proto.set_dq(private_key_subtle.dq);
- private_key_proto.set_crt(private_key_subtle.crt);
+ private_key_proto.set_d(
+ std::string(util::SecretDataAsStringView(private_key_subtle.d)));
+ private_key_proto.set_p(
+ std::string(util::SecretDataAsStringView(private_key_subtle.p)));
+ private_key_proto.set_q(
+ std::string(util::SecretDataAsStringView(private_key_subtle.q)));
+ private_key_proto.set_dp(
+ std::string(util::SecretDataAsStringView(private_key_subtle.dp)));
+ private_key_proto.set_dq(
+ std::string(util::SecretDataAsStringView(private_key_subtle.dq)));
+ private_key_proto.set_crt(
+ std::string(util::SecretDataAsStringView(private_key_subtle.crt)));
// Inner RSA Public key parameters.
RsaSsaPkcs1PublicKey* public_key_proto =
@@ -315,6 +328,8 @@
new PublicKeyVerifyPemKeysetReader(pem_serialized_keys_));
}
}
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "Unknown pem_reader_type_");
}
util::StatusOr<std::unique_ptr<Keyset>> PublicKeySignPemKeysetReader::Read() {
diff --git a/cc/signature/signature_pem_keyset_reader_test.cc b/cc/signature/signature_pem_keyset_reader_test.cc
index c7dcaed..dea6344 100644
--- a/cc/signature/signature_pem_keyset_reader_test.cc
+++ b/cc/signature/signature_pem_keyset_reader_test.cc
@@ -31,6 +31,7 @@
#include "tink/subtle/pem_parser_boringssl.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/enums.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/test_matchers.h"
#include "proto/common.pb.h"
@@ -141,12 +142,18 @@
RsaSsaPssPrivateKey private_key_proto;
private_key_proto.set_version(key_version);
- private_key_proto.set_d(key_subtle->d);
- private_key_proto.set_p(key_subtle->p);
- private_key_proto.set_q(key_subtle->q);
- private_key_proto.set_dp(key_subtle->dp);
- private_key_proto.set_dq(key_subtle->dq);
- private_key_proto.set_crt(key_subtle->crt);
+ private_key_proto.set_d(
+ std::string(util::SecretDataAsStringView(key_subtle->d)));
+ private_key_proto.set_p(
+ std::string(util::SecretDataAsStringView(key_subtle->p)));
+ private_key_proto.set_q(
+ std::string(util::SecretDataAsStringView(key_subtle->q)));
+ private_key_proto.set_dp(
+ std::string(util::SecretDataAsStringView(key_subtle->dp)));
+ private_key_proto.set_dq(
+ std::string(util::SecretDataAsStringView(key_subtle->dq)));
+ private_key_proto.set_crt(
+ std::string(util::SecretDataAsStringView(key_subtle->crt)));
// Set public key parameters.
RsaSsaPssPublicKey* public_key_proto = private_key_proto.mutable_public_key();
diff --git a/cc/subtle/BUILD.bazel b/cc/subtle/BUILD.bazel
index 0cb486e..9d107ed 100644
--- a/cc/subtle/BUILD.bazel
+++ b/cc/subtle/BUILD.bazel
@@ -254,6 +254,7 @@
"//util:status",
"//util:statusor",
"@boringssl//:crypto",
+ "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
],
)
@@ -288,6 +289,7 @@
"//util:status",
"//util:statusor",
"@boringssl//:crypto",
+ "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
],
)
@@ -302,6 +304,7 @@
":subtle_util",
":subtle_util_boringssl",
"//:aead",
+ "//config:tink_fips",
"//util:errors",
"//util:secret_data",
"//util:status",
@@ -421,6 +424,7 @@
":subtle_util",
":subtle_util_boringssl",
"//:aead",
+ "//config:tink_fips",
"//util:errors",
"//util:secret_data",
"//util:status",
@@ -463,6 +467,7 @@
":random",
":subtle_util",
":subtle_util_boringssl",
+ "//config:tink_fips",
"//util:secret_data",
"//util:status",
"//util:statusor",
@@ -494,6 +499,7 @@
":subtle_util",
":subtle_util_boringssl",
"//:aead",
+ "//config:tink_fips",
"//util:errors",
"//util:secret_data",
"//util:status",
@@ -534,6 +540,7 @@
":random",
":subtle_util",
"//:aead",
+ "//config:tink_fips",
"//util:secret_data",
"//util:status",
"//util:statusor",
@@ -566,6 +573,7 @@
include_prefix = "tink/subtle",
deps = [
":common_enums",
+ "//config:tink_fips",
"//util:errors",
"//util:secret_data",
"//util:status",
@@ -683,6 +691,7 @@
deps = [
":test_util",
"//:aead",
+ "//aead:cord_aead",
"//util:status",
"@com_google_absl//absl/strings",
],
@@ -916,9 +925,11 @@
":aes_gcm_boringssl",
":wycheproof_util",
"//:aead",
+ "//config:tink_fips",
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -1025,6 +1036,7 @@
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -1065,6 +1077,7 @@
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@com_google_googletest//:gtest_main",
],
@@ -1086,6 +1099,7 @@
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -1275,6 +1289,7 @@
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@boringssl//:crypto",
"@com_google_absl//absl/strings",
@@ -1331,6 +1346,7 @@
":ec_util",
":subtle_util_boringssl",
":wycheproof_util",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
@@ -1353,6 +1369,7 @@
"//util:secret_data",
"//util:status",
"//util:statusor",
+ "//util:test_matchers",
"//util:test_util",
"@boringssl//:crypto",
"@com_google_absl//absl/strings",
@@ -1521,6 +1538,7 @@
deps = [
":pem_parser_boringssl",
":subtle_util_boringssl",
+ "//util:secret_data",
"//util:status",
"//util:statusor",
"//util:test_matchers",
diff --git a/cc/subtle/CMakeLists.txt b/cc/subtle/CMakeLists.txt
index 5bffed8..3fb416f 100644
--- a/cc/subtle/CMakeLists.txt
+++ b/cc/subtle/CMakeLists.txt
@@ -243,6 +243,7 @@
tink::util::status
tink::util::statusor
crypto
+ absl::memory
absl::strings
)
@@ -275,6 +276,7 @@
tink::util::status
tink::util::statusor
crypto
+ absl::memory
absl::strings
)
@@ -284,6 +286,7 @@
aes_gcm_boringssl.cc
aes_gcm_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::random
tink::subtle::subtle_util
tink::subtle::subtle_util_boringssl
@@ -396,6 +399,7 @@
aes_eax_boringssl.cc
aes_eax_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::random
tink::subtle::subtle_util
tink::subtle::subtle_util_boringssl
@@ -436,6 +440,7 @@
aes_ctr_boringssl.cc
aes_ctr_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::ind_cpa_cipher
tink::subtle::random
tink::subtle::subtle_util
@@ -463,6 +468,7 @@
xchacha20_poly1305_boringssl.cc
xchacha20_poly1305_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::common_enums
tink::subtle::random
tink::subtle::subtle_util
@@ -501,6 +507,7 @@
aes_gcm_siv_boringssl.cc
aes_gcm_siv_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::random
tink::subtle::subtle_util
tink::core::aead
@@ -534,6 +541,7 @@
subtle_util_boringssl.cc
subtle_util_boringssl.h
DEPS
+ tink::config::tink_fips
tink::subtle::common_enums
tink::util::errors
tink::util::secret_data
@@ -638,6 +646,7 @@
DEPS
absl::strings
tink::core::aead
+ tink::aead::cord_aead
tink::util::status
)
@@ -831,10 +840,12 @@
DEPS
tink::subtle::aes_gcm_boringssl
tink::subtle::wycheproof_util
+ tink::config::tink_fips
tink::core::aead
tink::util::secret_data
tink::util::status
tink::util::statusor
+ tink::util::test_matchers
tink::util::test_util
absl::strings
gmock
@@ -923,6 +934,7 @@
tink::core::aead
tink::util::secret_data
tink::util::status
+ tink::util::test_matchers
tink::util::statusor
tink::util::test_util
absl::strings
@@ -956,6 +968,7 @@
tink::util::secret_data
tink::util::status
tink::util::statusor
+ tink::util::test_matchers
tink::util::test_util
)
@@ -971,6 +984,7 @@
tink::util::secret_data
tink::util::status
tink::util::statusor
+ tink::util::test_matchers
tink::util::test_util
absl::strings
rapidjson
@@ -1118,6 +1132,7 @@
crypto
absl::strings
rapidjson
+ gmock
)
tink_cc_test(
@@ -1152,6 +1167,7 @@
tink::subtle::ec_util
tink::subtle::subtle_util_boringssl
tink::subtle::wycheproof_util
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_matchers
@@ -1170,6 +1186,7 @@
tink::util::secret_data
tink::util::status
tink::util::statusor
+ tink::util::test_matchers
tink::util::test_util
crypto
absl::strings
@@ -1316,6 +1333,7 @@
DEPS
tink::subtle::pem_parser_boringssl
tink::subtle::subtle_util_boringssl
+ tink::util::secret_data
tink::util::status
tink::util::statusor
tink::util::test_util
diff --git a/cc/subtle/aead_test_util.cc b/cc/subtle/aead_test_util.cc
index df123d1..86f7d16 100644
--- a/cc/subtle/aead_test_util.cc
+++ b/cc/subtle/aead_test_util.cc
@@ -23,13 +23,33 @@
using ::crypto::tink::util::StatusOr;
-crypto::tink::util::Status EncryptThenDecrypt(Aead* encrypter, Aead* decrypter,
+crypto::tink::util::Status EncryptThenDecrypt(const Aead& encrypter,
+ const Aead& decrypter,
absl::string_view message,
absl::string_view aad) {
- StatusOr<std::string> encryption_or = encrypter->Encrypt(message, aad);
+ StatusOr<std::string> encryption_or = encrypter.Encrypt(message, aad);
if (!encryption_or.status().ok()) return encryption_or.status();
StatusOr<std::string> decryption_or =
- decrypter->Decrypt(encryption_or.ValueOrDie(), aad);
+ decrypter.Decrypt(encryption_or.ValueOrDie(), aad);
+ if (!decryption_or.status().ok()) return decryption_or.status();
+ if (decryption_or.ValueOrDie() != message) {
+ return crypto::tink::util::Status(crypto::tink::util::error::INTERNAL,
+ "Message/Decryption mismatch");
+ }
+ return util::OkStatus();
+}
+
+crypto::tink::util::Status EncryptThenDecrypt(const CordAead& encrypter,
+ const CordAead& decrypter,
+ absl::string_view message,
+ absl::string_view aad) {
+ absl::Cord message_cord = absl::Cord(message);
+ absl::Cord aad_cord = absl::Cord(aad);
+ StatusOr<absl::Cord> encryption_or =
+ encrypter.Encrypt(message_cord, aad_cord);
+ if (!encryption_or.status().ok()) return encryption_or.status();
+ StatusOr<absl::Cord> decryption_or =
+ decrypter.Decrypt(encryption_or.ValueOrDie(), aad_cord);
if (!decryption_or.status().ok()) return decryption_or.status();
if (decryption_or.ValueOrDie() != message) {
return crypto::tink::util::Status(crypto::tink::util::error::INTERNAL,
diff --git a/cc/subtle/aead_test_util.h b/cc/subtle/aead_test_util.h
index 541f74f..c4fec32 100644
--- a/cc/subtle/aead_test_util.h
+++ b/cc/subtle/aead_test_util.h
@@ -16,6 +16,7 @@
#include "absl/strings/string_view.h"
#include "tink/aead.h"
+#include "tink/aead/cord_aead.h"
#include "tink/util/status.h"
namespace crypto {
@@ -23,7 +24,15 @@
// Encrypt, then decrypt. Any error will be propagated to the caller. Returns OK
// if the resulting decryption is equal to the plaintext.
-crypto::tink::util::Status EncryptThenDecrypt(Aead* encrypter, Aead* decrypter,
+crypto::tink::util::Status EncryptThenDecrypt(const Aead& encrypter,
+ const Aead& decrypter,
+ absl::string_view message,
+ absl::string_view aad);
+
+// Encrypt, then decrypt. Any error will be propagated to the caller. Returns OK
+// if the resulting decryption is equal to the plaintext.
+crypto::tink::util::Status EncryptThenDecrypt(const CordAead& encrypter,
+ const CordAead& decrypter,
absl::string_view message,
absl::string_view aad);
diff --git a/cc/subtle/aead_test_util_test.cc b/cc/subtle/aead_test_util_test.cc
index a78c4a8..2b4b0bd 100644
--- a/cc/subtle/aead_test_util_test.cc
+++ b/cc/subtle/aead_test_util_test.cc
@@ -28,13 +28,13 @@
TEST(EncryptThenDecrypt, Basic) {
test::DummyAead aead("Aead 1");
- EXPECT_THAT(EncryptThenDecrypt(&aead, &aead, "plaintext", "aad"), IsOk());
+ EXPECT_THAT(EncryptThenDecrypt(aead, aead, "plaintext", "aad"), IsOk());
}
TEST(EncryptThenDecrypt, DifferentAeads) {
test::DummyAead aead_1("Aead 1");
test::DummyAead aead_2("Aead 2");
- EXPECT_THAT(EncryptThenDecrypt(&aead_1, &aead_2, "plaintext", "aad"),
+ EXPECT_THAT(EncryptThenDecrypt(aead_1, aead_2, "plaintext", "aad"),
Not(IsOk()));
}
diff --git a/cc/subtle/aes_cmac_boringssl.cc b/cc/subtle/aes_cmac_boringssl.cc
index e7329c0..4a9dce1 100644
--- a/cc/subtle/aes_cmac_boringssl.cc
+++ b/cc/subtle/aes_cmac_boringssl.cc
@@ -20,6 +20,7 @@
#include "absl/memory/memory.h"
#include "openssl/cmac.h"
+#include "openssl/mem.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/status.h"
@@ -76,11 +77,7 @@
return util::Status(util::error::INTERNAL,
"BoringSSL failed to compute CMAC");
}
- uint8_t diff = 0;
- for (uint32_t i = 0; i < tag_size_; i++) {
- diff |= buf[i] ^ static_cast<uint8_t>(mac[i]);
- }
- if (diff != 0) {
+ if (CRYPTO_memcmp(buf, mac.data(), tag_size_) != 0) {
return util::Status(util::error::INVALID_ARGUMENT, "verification failed");
}
return util::OkStatus();
diff --git a/cc/subtle/aes_ctr_boringssl.cc b/cc/subtle/aes_ctr_boringssl.cc
index cc89cea..4cdb8b4 100644
--- a/cc/subtle/aes_ctr_boringssl.cc
+++ b/cc/subtle/aes_ctr_boringssl.cc
@@ -20,6 +20,7 @@
#include "absl/memory/memory.h"
#include "openssl/evp.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
@@ -31,6 +32,9 @@
util::StatusOr<std::unique_ptr<IndCpaCipher>> AesCtrBoringSsl::New(
util::SecretData key, int iv_size) {
+ auto status = CheckFipsCompatibility<AesCtrBoringSsl>();
+ if (!status.ok()) return status;
+
const EVP_CIPHER* cipher =
SubtleUtilBoringSSL::GetAesCtrCipherForKeySize(key.size());
if (cipher == nullptr) {
diff --git a/cc/subtle/aes_ctr_boringssl.h b/cc/subtle/aes_ctr_boringssl.h
index f49b6bb..f6832a2 100644
--- a/cc/subtle/aes_ctr_boringssl.h
+++ b/cc/subtle/aes_ctr_boringssl.h
@@ -21,6 +21,7 @@
#include <utility>
#include "openssl/evp.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/ind_cpa_cipher.h"
#include "tink/util/secret_data.h"
#include "tink/util/statusor.h"
@@ -40,6 +41,9 @@
crypto::tink::util::StatusOr<std::string> Decrypt(
absl::string_view ciphertext) const override;
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kRequiresBoringCrypto;
+
private:
static constexpr int kMinIvSizeInBytes = 12;
static constexpr int kBlockSize = 16;
diff --git a/cc/subtle/aes_ctr_boringssl_test.cc b/cc/subtle/aes_ctr_boringssl_test.cc
index 9cac0e0..4c2f66f 100644
--- a/cc/subtle/aes_ctr_boringssl_test.cc
+++ b/cc/subtle/aes_ctr_boringssl_test.cc
@@ -24,6 +24,7 @@
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
@@ -31,7 +32,15 @@
namespace subtle {
namespace {
-TEST(AesCtrBoringSslTest, testEncryptDecrypt) {
+using ::crypto::tink::test::IsOk;
+using ::crypto::tink::test::StatusIs;
+
+TEST(AesCtrBoringSslTest, TestEncryptDecrypt) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
int iv_size = 12;
@@ -47,7 +56,12 @@
EXPECT_EQ(pt.ValueOrDie(), message);
}
-TEST(AesCtrBoringSslTest, testEncryptDecrypt_randomMessage) {
+TEST(AesCtrBoringSslTest, TestEncryptDecrypt_randomMessage) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
int iv_size = 12;
@@ -65,7 +79,12 @@
}
}
-TEST(AesCtrBoringSslTest, testEncryptDecrypt_randomKey_randomMessage) {
+TEST(AesCtrBoringSslTest, TestEncryptDecrypt_randomKey_randomMessage) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
for (int i = 0; i < 256; i++) {
util::SecretData key = Random::GetRandomKeyBytes(16);
int iv_size = 12;
@@ -82,7 +101,12 @@
}
}
-TEST(AesCtrBoringSslTest, testEncryptDecrypt_invalidIvSize) {
+TEST(AesCtrBoringSslTest, TestEncryptDecrypt_invalidIvSize) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
int iv_size = 11;
@@ -94,7 +118,12 @@
EXPECT_FALSE(res2.ok()) << res2.status();
}
-TEST(AesCtrBoringSslTest, testNistTestVector) {
+TEST(AesCtrBoringSslTest, TestNistTestVector) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
// NIST SP 800-38A pp 55.
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("2b7e151628aed2a6abf7158809cf4f3c"));
@@ -110,7 +139,12 @@
EXPECT_EQ(pt.ValueOrDie(), message);
}
-TEST(AesCtrBoringSslTest, testMultipleEncrypt) {
+TEST(AesCtrBoringSslTest, TestMultipleEncrypt) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = Random::GetRandomKeyBytes(16);
int iv_size = 12;
auto res = AesCtrBoringSsl::New(key, iv_size);
@@ -122,6 +156,38 @@
EXPECT_NE(ct1.ValueOrDie(), ct2.ValueOrDie());
}
+TEST(AesCtrBoringSslTest, TestFipsOnly) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesCtrBoringSsl::New(key128, 16).status(), IsOk());
+ EXPECT_THAT(subtle::AesCtrBoringSsl::New(key256, 16).status(), IsOk());
+}
+
+TEST(AesCtrBoringSslTest, TestFipsFailWithoutBoringCrypto) {
+ if (!kUseOnlyFips || FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesCtrBoringSsl::New(key128, 16).status(),
+ StatusIs(util::error::INTERNAL));
+ EXPECT_THAT(subtle::AesCtrBoringSsl::New(key256, 16).status(),
+ StatusIs(util::error::INTERNAL));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/aes_eax_boringssl.cc b/cc/subtle/aes_eax_boringssl.cc
index 5fea7c7..60b7c4b 100644
--- a/cc/subtle/aes_eax_boringssl.cc
+++ b/cc/subtle/aes_eax_boringssl.cc
@@ -28,6 +28,7 @@
#include "openssl/err.h"
#include "openssl/evp.h"
#include "tink/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
@@ -104,9 +105,9 @@
uint64_t in_low = BigEndianLoad64(in + 8);
uint64_t out_high = (in_high << 1) ^ (in_low >> 63);
// If the most significant bit is set then the result has to
- // be reduced by x^128 + x^7 + x^4 + x^2 + x + 1.
- // The representation of x^7 + x^4 + x^2 + x + 1 is 0x87.
- uint64_t out_low = (in_low << 1) ^ (in_high >> 63 ? 0x87 : 0);
+ // be reduced by x^128 + x^7 + x^2 + x + 1.
+ // The representation of x^7 + x^2 + x + 1 is 0x87.
+ uint64_t out_low = (in_low << 1) ^ (0x87 & -(in_high >> 63));
BigEndianStore64(out_high, out);
BigEndianStore64(out_low, out + 8);
}
@@ -143,6 +144,9 @@
crypto::tink::util::StatusOr<std::unique_ptr<Aead>> AesEaxBoringSsl::New(
const util::SecretData& key, size_t nonce_size_in_bytes) {
+ auto status = CheckFipsCompatibility<AesEaxBoringSsl>();
+ if (!status.ok()) return status;
+
if (!IsValidKeySize(key.size())) {
return util::Status(util::error::INVALID_ARGUMENT, "Invalid key size");
}
diff --git a/cc/subtle/aes_eax_boringssl.h b/cc/subtle/aes_eax_boringssl.h
index 9ad825f..2f4263c 100644
--- a/cc/subtle/aes_eax_boringssl.h
+++ b/cc/subtle/aes_eax_boringssl.h
@@ -24,6 +24,7 @@
#include "absl/types/span.h"
#include "openssl/aes.h"
#include "openssl/evp.h"
+#include "tink/config/tink_fips.h"
#include "tink/aead.h"
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
@@ -50,6 +51,9 @@
absl::string_view ciphertext,
absl::string_view additional_data) const override;
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kNotFips;
+
private:
static constexpr int kTagSize = 16;
static constexpr int kBlockSize = 16;
diff --git a/cc/subtle/aes_eax_boringssl_test.cc b/cc/subtle/aes_eax_boringssl_test.cc
index e1fd3a0..b9cce21 100644
--- a/cc/subtle/aes_eax_boringssl_test.cc
+++ b/cc/subtle/aes_eax_boringssl_test.cc
@@ -26,6 +26,7 @@
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
@@ -33,7 +34,13 @@
namespace subtle {
namespace {
-TEST(AesEaxBoringSslTest, testBasic) {
+using ::crypto::tink::test::StatusIs;
+
+TEST(AesEaxBoringSslTest, TestBasic) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
size_t nonce_size = 12;
@@ -50,7 +57,11 @@
EXPECT_EQ(pt.ValueOrDie(), message);
}
-TEST(AesEaxBoringSslTest, testMessageSize) {
+TEST(AesEaxBoringSslTest, TestMessageSize) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
size_t nonce_size = 12;
@@ -69,7 +80,11 @@
}
}
-TEST(AesEaxBoringSslTest, testAadSize) {
+TEST(AesEaxBoringSslTest, TestAadSize) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
size_t nonce_size = 12;
@@ -88,7 +103,11 @@
}
}
-TEST(AesEaxBoringSslTest, testLongNonce) {
+TEST(AesEaxBoringSslTest, TestLongNonce) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
size_t nonce_size = 16;
@@ -105,7 +124,11 @@
EXPECT_EQ(pt.ValueOrDie(), message);
}
-TEST(AesEaxBoringSslTest, testModification) {
+TEST(AesEaxBoringSslTest, TestModification) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
size_t nonce_size = 12;
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
@@ -134,7 +157,11 @@
}
}
-TEST(AesEaxBoringSslTest, testInvalidKeySizes) {
+TEST(AesEaxBoringSslTest, TestInvalidKeySizes) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
size_t nonce_size = 12;
for (int keysize = 0; keysize < 65; keysize++) {
if (keysize == 16 || keysize == 32) {
@@ -146,7 +173,11 @@
}
}
-TEST(AesEaxBoringSslTest, testEmpty) {
+TEST(AesEaxBoringSslTest, TestEmpty) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
size_t nonce_size = 12;
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("bedcfb5a011ebc84600fcb296c15af0d"));
@@ -279,11 +310,31 @@
}
TEST(AesEaxBoringSslTest, TestVectors) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
std::unique_ptr<rapidjson::Document> root =
WycheproofUtil::ReadTestVectors("aes_eax_test.json");
ASSERT_TRUE(WycheproofTest(*root));
}
+TEST(AesEaxBoringSslTest, TestFipsOnly) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesEaxBoringSsl::New(key128, 16).status(),
+ StatusIs(util::error::INTERNAL));
+ EXPECT_THAT(subtle::AesEaxBoringSsl::New(key256, 16).status(),
+ StatusIs(util::error::INTERNAL));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/aes_gcm_boringssl.cc b/cc/subtle/aes_gcm_boringssl.cc
index b0e5b9b..7991410 100644
--- a/cc/subtle/aes_gcm_boringssl.cc
+++ b/cc/subtle/aes_gcm_boringssl.cc
@@ -20,6 +20,7 @@
#include "absl/memory/memory.h"
#include "openssl/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
@@ -31,6 +32,9 @@
util::StatusOr<std::unique_ptr<Aead>> AesGcmBoringSsl::New(
const util::SecretData& key) {
+ auto status = CheckFipsCompatibility<AesGcmBoringSsl>();
+ if (!status.ok()) return status;
+
const EVP_AEAD* aead =
SubtleUtilBoringSSL::GetAesGcmAeadForKeySize(key.size());
if (aead == nullptr) {
diff --git a/cc/subtle/aes_gcm_boringssl.h b/cc/subtle/aes_gcm_boringssl.h
index ecfa2f0..fbe579f 100644
--- a/cc/subtle/aes_gcm_boringssl.h
+++ b/cc/subtle/aes_gcm_boringssl.h
@@ -23,6 +23,7 @@
#include "absl/base/macros.h"
#include "openssl/aead.h"
#include "tink/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/util/secret_data.h"
#include "tink/util/statusor.h"
@@ -48,6 +49,9 @@
absl::string_view ciphertext,
absl::string_view additional_data) const override;
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kRequiresBoringCrypto;
+
private:
static constexpr int kIvSizeInBytes = 12;
static constexpr int kTagSizeInBytes = 16;
diff --git a/cc/subtle/aes_gcm_boringssl_test.cc b/cc/subtle/aes_gcm_boringssl_test.cc
index 262738f..5506a39 100644
--- a/cc/subtle/aes_gcm_boringssl_test.cc
+++ b/cc/subtle/aes_gcm_boringssl_test.cc
@@ -24,10 +24,12 @@
#include "absl/strings/str_cat.h"
#include "openssl/err.h"
#include "include/rapidjson/document.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/wycheproof_util.h"
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
@@ -35,9 +37,16 @@
namespace subtle {
namespace {
+using ::crypto::tink::test::IsOk;
+using ::crypto::tink::test::StatusIs;
using ::testing::Eq;
TEST(AesGcmBoringSslTest, testBasic) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto res = AesGcmBoringSsl::New(key);
@@ -54,6 +63,11 @@
}
TEST(AesGcmBoringSslTest, testModification) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmBoringSsl::New(key).ValueOrDie());
@@ -83,6 +97,11 @@
void TestDecryptWithEmptyAad(crypto::tink::Aead* cipher, absl::string_view ct,
absl::string_view message) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
{ // AAD is a null string_view.
const absl::string_view aad;
auto pt_or_status = cipher->Decrypt(ct, aad);
@@ -105,6 +124,11 @@
}
TEST(AesGcmBoringSslTest, testAadEmptyVersusNullStringView) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
const util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmBoringSsl::New(key).ValueOrDie());
@@ -133,6 +157,11 @@
}
TEST(AesGcmBoringSslTest, testMessageEmptyVersusNullStringView) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
const util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmBoringSsl::New(key).ValueOrDie());
@@ -169,6 +198,11 @@
}
TEST(AesGcmBoringSslTest, testBothMessageAndAadEmpty) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
const util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmBoringSsl::New(key).ValueOrDie());
@@ -206,6 +240,11 @@
}
TEST(AesGcmBoringSslTest, testInvalidKeySizes) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
for (int keysize = 0; keysize < 65; keysize++) {
util::SecretData key(keysize, 'x');
auto cipher = AesGcmBoringSsl::New(key);
@@ -279,11 +318,48 @@
}
TEST(AesGcmBoringSslTest, TestVectors) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
std::unique_ptr<rapidjson::Document> root =
WycheproofUtil::ReadTestVectors("aes_gcm_test.json");
ASSERT_TRUE(WycheproofTest(*root));
}
+TEST(AesGcmBoringSslTest, TestFipsOnly) {
+ if (kUseOnlyFips && !FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesGcmBoringSsl::New(key128).status(), IsOk());
+ EXPECT_THAT(subtle::AesGcmBoringSsl::New(key256).status(), IsOk());
+}
+
+TEST(AesGcmBoringSslTest, TestFipsFailWithoutBoringCrypto) {
+ if (!kUseOnlyFips || FIPS_mode()) {
+ GTEST_SKIP()
+ << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesGcmBoringSsl::New(key128).status(),
+ StatusIs(util::error::INTERNAL));
+ EXPECT_THAT(subtle::AesGcmBoringSsl::New(key256).status(),
+ StatusIs(util::error::INTERNAL));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.cc b/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.cc
index efa4fce..b9a978a 100644
--- a/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.cc
+++ b/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.cc
@@ -144,9 +144,10 @@
if (aead == nullptr) {
return util::Status(util::error::INTERNAL, "invalid key size");
}
- if (EVP_AEAD_CTX_init(ctx_.get(), aead, key.data(), key.size(),
- AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes,
- nullptr) != 1) {
+ ctx_.reset(
+ EVP_AEAD_CTX_new(aead, key.data(), key.size(),
+ AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes));
+ if (!ctx_) {
return util::Status(util::error::INTERNAL,
"could not initialize EVP_AEAD_CTX");
}
diff --git a/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.h b/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.h
index 519d304..b553ce3 100644
--- a/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.h
+++ b/cc/subtle/aes_gcm_hkdf_stream_segment_decrypter.h
@@ -112,7 +112,7 @@
bool is_initialized_ = false;
std::vector<uint8_t> salt_;
std::vector<uint8_t> nonce_prefix_;
- bssl::ScopedEVP_AEAD_CTX ctx_;
+ bssl::UniquePtr<EVP_AEAD_CTX> ctx_;
};
} // namespace subtle
diff --git a/cc/subtle/aes_gcm_siv_boringssl.cc b/cc/subtle/aes_gcm_siv_boringssl.cc
index d2bfaec..9b8d699 100644
--- a/cc/subtle/aes_gcm_siv_boringssl.cc
+++ b/cc/subtle/aes_gcm_siv_boringssl.cc
@@ -21,6 +21,7 @@
#include "absl/memory/memory.h"
#include "openssl/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/subtle/subtle_util.h"
#include "tink/util/status.h"
@@ -44,6 +45,9 @@
util::StatusOr<std::unique_ptr<Aead>> AesGcmSivBoringSsl::New(
const util::SecretData& key) {
+ auto status = CheckFipsCompatibility<AesGcmSivBoringSsl>();
+ if (!status.ok()) return status;
+
const EVP_AEAD* aead = GetCipherForKeySize(key.size());
if (aead == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT, "invalid key size");
diff --git a/cc/subtle/aes_gcm_siv_boringssl.h b/cc/subtle/aes_gcm_siv_boringssl.h
index e46894a..7257075 100644
--- a/cc/subtle/aes_gcm_siv_boringssl.h
+++ b/cc/subtle/aes_gcm_siv_boringssl.h
@@ -23,6 +23,7 @@
#include "absl/strings/string_view.h"
#include "openssl/aead.h"
#include "tink/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/util/secret_data.h"
#include "tink/util/statusor.h"
@@ -60,6 +61,9 @@
absl::string_view ciphertext,
absl::string_view additional_data) const override;
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kNotFips;
+
private:
static constexpr int kIvSizeInBytes = 12;
static constexpr int kTagSizeInBytes = 16;
diff --git a/cc/subtle/aes_gcm_siv_boringssl_test.cc b/cc/subtle/aes_gcm_siv_boringssl_test.cc
index 9cd71f7..ef946b7 100644
--- a/cc/subtle/aes_gcm_siv_boringssl_test.cc
+++ b/cc/subtle/aes_gcm_siv_boringssl_test.cc
@@ -27,6 +27,7 @@
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
@@ -34,7 +35,13 @@
namespace subtle {
namespace {
+using ::crypto::tink::test::StatusIs;
+
TEST(AesGcmSivBoringSslTest, Basic) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto res = AesGcmSivBoringSsl::New(key);
@@ -55,6 +62,10 @@
}
TEST(AesGcmSivBoringSslTest, Sizes) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto res = AesGcmSivBoringSsl::New(key);
@@ -84,6 +95,10 @@
}
TEST(AesGcmSivBoringSslTest, Modification) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmSivBoringSsl::New(key).ValueOrDie());
@@ -114,6 +129,10 @@
}
TEST(AesGcmSivBoringSslTest, AadEmptyVersusNullStringView) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
const util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmSivBoringSsl::New(key).ValueOrDie());
@@ -169,6 +188,10 @@
}
TEST(AesGcmSivBoringSslTest, MessageEmptyVersusNullStringView) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
const util::SecretData key = util::SecretDataFromStringView(
test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(AesGcmSivBoringSsl::New(key).ValueOrDie());
@@ -205,6 +228,10 @@
}
TEST(AesGcmSivBoringSslTest, InvalidKeySizes) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
for (int keysize = 0; keysize < 65; keysize++) {
if (keysize == 16 || keysize == 32) {
continue;
@@ -268,11 +295,31 @@
}
TEST(AesGcmSivBoringSslTest, TestVectors) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
std::unique_ptr<rapidjson::Document> root =
WycheproofUtil::ReadTestVectors("aes_gcm_siv_test.json");
ASSERT_TRUE(WycheproofTest(*root));
}
+TEST(AesGcmSivBoringSslTest, TestFipsOnly) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ util::SecretData key128 = util::SecretDataFromStringView(
+ test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ EXPECT_THAT(subtle::AesGcmSivBoringSsl::New(key128).status(),
+ StatusIs(util::error::INTERNAL));
+ EXPECT_THAT(subtle::AesGcmSivBoringSsl::New(key256).status(),
+ StatusIs(util::error::INTERNAL));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/aes_siv_boringssl.cc b/cc/subtle/aes_siv_boringssl.cc
index 422973a..1b174bc 100644
--- a/cc/subtle/aes_siv_boringssl.cc
+++ b/cc/subtle/aes_siv_boringssl.cc
@@ -21,6 +21,7 @@
#include "absl/memory/memory.h"
#include "openssl/aes.h"
+#include "openssl/mem.h"
#include "tink/deterministic_aead.h"
#include "tink/util/errors.h"
#include "tink/util/status.h"
@@ -96,12 +97,13 @@
// static
void AesSivBoringSsl::MultiplyByX(uint8_t block[kBlockSize]) {
- // Cast to signed makes the left shift produce either 0x00 or 0xff.
- uint8_t carry = *reinterpret_cast<int8_t*>(&block[0]) >> 7;
+ // Carry over 0x87 if msb is 1 0x00 if msb is 0.
+ uint8_t carry = 0x87 & -(block[0] >> 7);
for (size_t i = 0; i < kBlockSize - 1; ++i) {
block[i] = (block[i] << 1) | (block[i + 1] >> 7);
}
- block[kBlockSize - 1] = (block[kBlockSize - 1] << 1) ^ (carry & 0x87);
+ block[kBlockSize - 1] =
+ (block[kBlockSize - 1] << 1) ^ carry;
}
// static
@@ -226,12 +228,7 @@
S2v(absl::MakeSpan(reinterpret_cast<const uint8_t*>(additional_data.data()),
additional_data.size()),
absl::MakeSpan(pt), s2v);
- // Compare the siv from the ciphertext with the recomputed siv
- uint8_t diff = 0;
- for (int i = 0; i < kBlockSize; ++i) {
- diff |= siv[i] ^ s2v[i];
- }
- if (diff != 0) {
+ if (CRYPTO_memcmp(siv, s2v, kBlockSize) != 0) {
return util::Status(util::error::INVALID_ARGUMENT, "invalid ciphertext");
}
return std::string(reinterpret_cast<const char*>(pt.data()), plaintext_size);
diff --git a/cc/subtle/ecdsa_sign_boringssl.cc b/cc/subtle/ecdsa_sign_boringssl.cc
index 1c044c6..38c84a0 100644
--- a/cc/subtle/ecdsa_sign_boringssl.cc
+++ b/cc/subtle/ecdsa_sign_boringssl.cc
@@ -99,8 +99,7 @@
}
bssl::UniquePtr<BIGNUM> priv_key(
- BN_bin2bn(reinterpret_cast<const unsigned char*>(ec_key.priv.data()),
- ec_key.priv.size(), nullptr));
+ BN_bin2bn(ec_key.priv.data(), ec_key.priv.size(), nullptr));
if (!EC_KEY_set_private_key(key.get(), priv_key.get())) {
return util::Status(util::error::INVALID_ARGUMENT,
absl::StrCat("Invalid private key: ",
diff --git a/cc/subtle/ecdsa_sign_boringssl.h b/cc/subtle/ecdsa_sign_boringssl.h
index 03f1280..5c1e7a1 100644
--- a/cc/subtle/ecdsa_sign_boringssl.h
+++ b/cc/subtle/ecdsa_sign_boringssl.h
@@ -42,8 +42,6 @@
crypto::tink::util::StatusOr<std::string> Sign(
absl::string_view data) const override;
- virtual ~EcdsaSignBoringSsl() {}
-
private:
EcdsaSignBoringSsl(bssl::UniquePtr<EC_KEY> key, const EVP_MD* hash,
EcdsaSignatureEncoding encoding);
diff --git a/cc/subtle/ecies_hkdf_sender_kem_boringssl_test.cc b/cc/subtle/ecies_hkdf_sender_kem_boringssl_test.cc
index a9efa63..70b3518 100644
--- a/cc/subtle/ecies_hkdf_sender_kem_boringssl_test.cc
+++ b/cc/subtle/ecies_hkdf_sender_kem_boringssl_test.cc
@@ -86,8 +86,7 @@
ASSERT_TRUE(status_or_kem_key.ok());
auto kem_key = std::move(status_or_kem_key.ValueOrDie());
auto ecies_recipient(
- std::move(EciesHkdfRecipientKemBoringSsl::New(
- test.curve, util::SecretDataFromStringView(test_key.priv))
+ std::move(EciesHkdfRecipientKemBoringSsl::New(test.curve, test_key.priv)
.ValueOrDie()));
auto status_or_shared_secret = ecies_recipient->GenerateKey(
kem_key->get_kem_bytes(), test.hash,
diff --git a/cc/subtle/encrypt_then_authenticate.cc b/cc/subtle/encrypt_then_authenticate.cc
index 7bc5652..92678be 100644
--- a/cc/subtle/encrypt_then_authenticate.cc
+++ b/cc/subtle/encrypt_then_authenticate.cc
@@ -16,6 +16,7 @@
#include "tink/subtle/encrypt_then_authenticate.h"
+#include <cstdint>
#include <string>
#include <vector>
@@ -66,7 +67,12 @@
std::string ciphertext(ct.ValueOrDie());
std::string toAuthData(additional_data);
toAuthData.append(ciphertext);
- uint64_t aad_size_in_bits = additional_data.size() * 8;
+ uint64_t aad_size_in_bytes = additional_data.size();
+ uint64_t aad_size_in_bits = aad_size_in_bytes * 8;
+ if (aad_size_in_bits / 8 != aad_size_in_bytes /* overflow occured! */) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "additional data too long");
+ }
toAuthData.append(longToBigEndianStr(aad_size_in_bits));
auto tag = mac_->ComputeMac(toAuthData);
if (!tag.ok()) {
@@ -92,7 +98,12 @@
.substr(0, ciphertext.size() - tag_size_);
std::string toAuthData(additional_data);
toAuthData.append(payload);
- uint64_t aad_size_in_bits = additional_data.size() * 8;
+ uint64_t aad_size_in_bytes = additional_data.size();
+ uint64_t aad_size_in_bits = aad_size_in_bytes * 8;
+ if (aad_size_in_bits / 8 != aad_size_in_bytes /* overflow occured! */) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "additional data too long");
+ }
toAuthData.append(longToBigEndianStr(aad_size_in_bits));
auto verified = mac_->VerifyMac(
ciphertext.substr(ciphertext.size() - tag_size_, tag_size_), toAuthData);
diff --git a/cc/subtle/encrypt_then_authenticate_test.cc b/cc/subtle/encrypt_then_authenticate_test.cc
index 1b9dc45..153bbe3 100644
--- a/cc/subtle/encrypt_then_authenticate_test.cc
+++ b/cc/subtle/encrypt_then_authenticate_test.cc
@@ -265,6 +265,46 @@
}
}
+// EncryptThenAuthenticate computes the MAC over aad || ciphertext ||
+// aad_size_in_bits, where aad_size_in_bits = aad_size() * 8 [1].
+// aad.size() returns a size_t which is usually unsigned long or unsigned long
+// long. On 32-bit machines (and maybe others), long is 32-bit int. If
+// aad.size() returns a number equal to or larger than 2^29, an overflow will
+// occur when multiplying with 8 to get the size in bits. This leads to an
+// authentication bypass vulnerability. This test ensures that the overflow
+// issue and the auth bypass vulnerability are fixed.
+TEST(EncryptThenAuthenticateTest, testAuthBypassShouldNotWork) {
+// Disable this test when running with ASYLO, because it allocates more memory
+// than ASYLO can handle.
+#ifndef __ASYLO__
+ int encryption_key_size = 16;
+ int iv_size = 12;
+ int mac_key_size = 16;
+ int tag_size = 16;
+ auto cipher = std::move(createAead(encryption_key_size, iv_size, mac_key_size,
+ tag_size, HashType::SHA1)
+ .ValueOrDie());
+
+ // Encrypt a message...
+ const std::string message = "Some data to encrypt.";
+ // ...with a long aad whose size in bits converted to an unsigned 32-bit
+ // integer is 0.
+ const std::string aad = std::string(1 << 29, 'a');
+ auto encrypted = cipher->Encrypt(message, aad);
+ EXPECT_TRUE(encrypted.ok()) << encrypted.status();
+ auto ct = encrypted.ValueOrDie();
+ auto decrypted = cipher->Decrypt(ct, aad);
+ EXPECT_TRUE(decrypted.ok()) << decrypted.status();
+
+ // Test that the 2^29-byte aad is NOT considered equal to an empty aad.
+ // That is, test that a valid tag for (ciphertext, aad) is INVALID for (aad
+ // + ciphertext, "").
+ ct = aad + ct;
+ decrypted = cipher->Decrypt(ct, "");
+ EXPECT_FALSE(decrypted.ok());
+#endif // __ASYLO__
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/hmac_boringssl.cc b/cc/subtle/hmac_boringssl.cc
index 063d530..6fd6c64 100644
--- a/cc/subtle/hmac_boringssl.cc
+++ b/cc/subtle/hmac_boringssl.cc
@@ -29,6 +29,7 @@
#include "openssl/err.h"
#include "openssl/evp.h"
#include "openssl/hmac.h"
+#include "openssl/mem.h"
namespace crypto {
@@ -96,11 +97,7 @@
return util::Status(util::error::INTERNAL,
"BoringSSL failed to compute HMAC");
}
- uint8_t diff = 0;
- for (uint32_t i = 0; i < tag_size_; i++) {
- diff |= buf[i] ^ static_cast<uint8_t>(mac[i]);
- }
- if (diff != 0) {
+ if (CRYPTO_memcmp(buf, mac.data(), tag_size_) != 0) {
return util::Status(util::error::INVALID_ARGUMENT, "verification failed");
}
return util::Status::OK;
diff --git a/cc/subtle/pem_parser_boringssl.cc b/cc/subtle/pem_parser_boringssl.cc
index 0063d1a..6e2d3b6 100644
--- a/cc/subtle/pem_parser_boringssl.cc
+++ b/cc/subtle/pem_parser_boringssl.cc
@@ -52,6 +52,104 @@
return util::OkStatus();
}
+// Converts the public portion of a given SubtleUtilBoringSSL::EcKey,
+// `subtle_ec_key`, into an OpenSSL EC key, `openssl_ec_key`.
+util::Status ConvertSubtleEcKeyToOpenSslEcPublicKey(
+ const SubtleUtilBoringSSL::EcKey& subtle_ec_key, EC_KEY* openssl_ec_key) {
+ if (openssl_ec_key == nullptr) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "`openssl_ec_key` arg cannot be NULL");
+ }
+
+ // Set the key's group (EC curve).
+ auto group_statusor = SubtleUtilBoringSSL::GetEcGroup(subtle_ec_key.curve);
+ if (!group_statusor.ok()) {
+ return group_statusor.status();
+ }
+ bssl::UniquePtr<EC_GROUP> group(group_statusor.ValueOrDie());
+ if (group.get() == nullptr) {
+ return util::Status(
+ util::error::INTERNAL,
+ absl::StrCat("failed to set EC group to curve ", subtle_ec_key.curve));
+ }
+ if (!EC_KEY_set_group(openssl_ec_key, group.get())) {
+ return util::Status(
+ util::error::INTERNAL,
+ absl::StrCat("failed to set key group from EC group for curve ",
+ subtle_ec_key.curve));
+ }
+
+ // Create an EC point and initialize it from the key proto.
+ bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
+ if (!point.get()) {
+ return util::Status(util::error::INTERNAL, "failed to allocate EC_POINT");
+ }
+ bssl::UniquePtr<BIGNUM> x(BN_bin2bn(
+ reinterpret_cast<const unsigned char*>(subtle_ec_key.pub_x.data()),
+ subtle_ec_key.pub_x.length(), nullptr));
+ bssl::UniquePtr<BIGNUM> y(BN_bin2bn(
+ reinterpret_cast<const unsigned char*>(subtle_ec_key.pub_y.data()),
+ subtle_ec_key.pub_y.length(), nullptr));
+ if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(),
+ y.get(), nullptr)) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to set affine coordinates");
+ }
+ if (!EC_POINT_is_on_curve(group.get(), point.get(), nullptr)) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to confirm EC point is on curve");
+ }
+
+ // Set the key's point from the EC point, created above.
+ if (!EC_KEY_set_public_key(openssl_ec_key, point.get())) {
+ return util::Status(util::error::INTERNAL, "failed to set public key");
+ }
+
+ return util::OkStatus();
+}
+
+// Converts a given SubtleUtilBoringSSL::EcKey, `subtle_ec_key`, into an OpenSSL
+// EC key, `openssl_ec_key`.
+util::Status ConvertSubtleEcKeyToOpenSslEcPrivateKey(
+ const SubtleUtilBoringSSL::EcKey& subtle_ec_key, EC_KEY* openssl_ec_key) {
+ if (openssl_ec_key == nullptr) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "`openssl_ec_key` arg cannot be NULL");
+ }
+ util::Status status =
+ ConvertSubtleEcKeyToOpenSslEcPublicKey(subtle_ec_key, openssl_ec_key);
+ if (!status.ok()) {
+ return status;
+ }
+ bssl::UniquePtr<BIGNUM> x(BN_bin2bn(
+ reinterpret_cast<const unsigned char*>(subtle_ec_key.priv.data()),
+ subtle_ec_key.priv.size(), nullptr));
+ if (!EC_KEY_set_private_key(openssl_ec_key, x.get())) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to set private key");
+ }
+ if (!EC_KEY_check_key(openssl_ec_key)) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed private key check");
+ }
+ return util::OkStatus();
+}
+
+// Converts an OpenSSL BIO (i.e., basic IO stream), `bio`, into a string.
+util::StatusOr<std::string> ConvertBioToString(BIO* bio) {
+ BUF_MEM* mem = nullptr;
+ BIO_get_mem_ptr(bio, &mem);
+ std::string pem_material;
+ if (mem->data && mem->length) {
+ pem_material.assign(mem->data, mem->length);
+ }
+ if (pem_material.empty()) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to retrieve key material from BIO");
+ }
+ return pem_material;
+}
+
} // namespace
// static.
@@ -131,7 +229,8 @@
absl::make_unique<SubtleUtilBoringSSL::RsaPrivateKey>();
auto n_str = SubtleUtilBoringSSL::bn2str(n_bn, BN_num_bytes(n_bn));
auto e_str = SubtleUtilBoringSSL::bn2str(e_bn, BN_num_bytes(e_bn));
- auto d_str = SubtleUtilBoringSSL::bn2str(d_bn, BN_num_bytes(d_bn));
+ auto d_str =
+ SubtleUtilBoringSSL::BignumToSecretData(d_bn, BN_num_bytes(d_bn));
if (!n_str.ok()) return n_str.status();
if (!e_str.ok()) return e_str.status();
if (!d_str.ok()) return d_str.status();
@@ -142,8 +241,10 @@
// Save factors.
const BIGNUM *p_bn, *q_bn;
RSA_get0_factors(bssl_rsa_key, &p_bn, &q_bn);
- auto p_str = SubtleUtilBoringSSL::bn2str(p_bn, BN_num_bytes(p_bn));
- auto q_str = SubtleUtilBoringSSL::bn2str(q_bn, BN_num_bytes(q_bn));
+ auto p_str =
+ SubtleUtilBoringSSL::BignumToSecretData(p_bn, BN_num_bytes(p_bn));
+ auto q_str =
+ SubtleUtilBoringSSL::BignumToSecretData(q_bn, BN_num_bytes(q_bn));
if (!p_str.ok()) return p_str.status();
if (!q_str.ok()) return q_str.status();
rsa_private_key->p = std::move(p_str.ValueOrDie());
@@ -152,9 +253,12 @@
// Save CRT parameters.
const BIGNUM *dp_bn, *dq_bn, *crt_bn;
RSA_get0_crt_params(bssl_rsa_key, &dp_bn, &dq_bn, &crt_bn);
- auto dp_str = SubtleUtilBoringSSL::bn2str(dp_bn, BN_num_bytes(dp_bn));
- auto dq_str = SubtleUtilBoringSSL::bn2str(dq_bn, BN_num_bytes(dq_bn));
- auto crt_str = SubtleUtilBoringSSL::bn2str(crt_bn, BN_num_bytes(crt_bn));
+ auto dp_str =
+ SubtleUtilBoringSSL::BignumToSecretData(dp_bn, BN_num_bytes(dp_bn));
+ auto dq_str =
+ SubtleUtilBoringSSL::BignumToSecretData(dq_bn, BN_num_bytes(dq_bn));
+ auto crt_str =
+ SubtleUtilBoringSSL::BignumToSecretData(crt_bn, BN_num_bytes(crt_bn));
if (!dp_str.ok()) return dp_str.status();
if (!dq_str.ok()) return dq_str.status();
if (!crt_str.ok()) return crt_str.status();
@@ -177,6 +281,40 @@
"PEM EC Private Key parsing is unimplemented");
}
+util::StatusOr<std::string> PemParser::WriteEcPublicKey(
+ const SubtleUtilBoringSSL::EcKey& ec_key) {
+ bssl::UniquePtr<EC_KEY> openssl_ec_key(EC_KEY_new());
+ util::Status status =
+ ConvertSubtleEcKeyToOpenSslEcPublicKey(ec_key, openssl_ec_key.get());
+ if (!status.ok()) {
+ return status;
+ }
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ if (!PEM_write_bio_EC_PUBKEY(bio.get(), openssl_ec_key.get())) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to write openssl EC key to write bio");
+ }
+ return ConvertBioToString(bio.get());
+}
+
+util::StatusOr<std::string> PemParser::WriteEcPrivateKey(
+ const SubtleUtilBoringSSL::EcKey& ec_key) {
+ bssl::UniquePtr<EC_KEY> openssl_ec_key(EC_KEY_new());
+ util::Status status =
+ ConvertSubtleEcKeyToOpenSslEcPrivateKey(ec_key, openssl_ec_key.get());
+ if (!status.ok()) {
+ return status;
+ }
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ if (!PEM_write_bio_ECPrivateKey(bio.get(), openssl_ec_key.get(),
+ /*enc=*/nullptr, /*kstr=*/nullptr, /*klen=*/0,
+ /*cb=*/nullptr, /*u=*/nullptr)) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "failed to write openssl EC key to write bio");
+ }
+ return ConvertBioToString(bio.get());
+}
+
} // namespace subtle
} // namespace tink
} // namespace crypto
diff --git a/cc/subtle/pem_parser_boringssl.h b/cc/subtle/pem_parser_boringssl.h
index b205bee..61914ea 100644
--- a/cc/subtle/pem_parser_boringssl.h
+++ b/cc/subtle/pem_parser_boringssl.h
@@ -47,6 +47,16 @@
// SubtleUtilBoringSSL::EcKey.
static util::StatusOr<std::unique_ptr<SubtleUtilBoringSSL::EcKey>>
ParseEcPrivateKey(absl::string_view pem_serialized_key);
+
+ // Writes a given SubtleUtilBoringSSL::EcKey `ec_key` into a PEM serialized
+ // EC public key.
+ static util::StatusOr<std::string> WriteEcPublicKey(
+ const SubtleUtilBoringSSL::EcKey& ec_key);
+
+ // Writes a given SubtleUtilBoringSSL::EcKey `ec_key` into a PEM serialized
+ // EC private key.
+ static util::StatusOr<std::string> WriteEcPrivateKey(
+ const SubtleUtilBoringSSL::EcKey& ec_key);
};
} // namespace subtle
diff --git a/cc/subtle/pem_parser_boringssl_test.cc b/cc/subtle/pem_parser_boringssl_test.cc
index 2e7d3d7..8ee9522 100644
--- a/cc/subtle/pem_parser_boringssl_test.cc
+++ b/cc/subtle/pem_parser_boringssl_test.cc
@@ -20,6 +20,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "openssl/base.h"
#include "openssl/bio.h"
@@ -28,6 +30,7 @@
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "tink/subtle/subtle_util_boringssl.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
@@ -38,6 +41,177 @@
namespace subtle {
namespace {
+using ::crypto::tink::test::StatusIs;
+
+// Test vectors for ECDSA were generated using the `openssl` command.
+//
+// 1. Generate private PEM file. In the command below, the following values were
+// used for the -name flag: {prime256v1, secp384r1, secp521r1}.
+//
+// $ openssl ecparam -genkey -name prime256v1 -noout -out ec-key-pair.pem
+//
+// 2. Generate public PEM file from private PEM file.
+//
+// $ openssl ec -in ec-key-pair.pem -pubout -out pub.pem
+//
+// 3. Print public X, Y and private key components. The public component is
+// obtained by removing the leading "04" character (which indicates that the key
+// is not compressed) and splitting the remaning bytes in two. The first half is
+// X and the 2nd half is Y.
+//
+// $ openssl ec -in ec-key-pair.pem -text -param_enc explicit -noout
+struct EcKeyTestVector {
+ // EC format
+ subtle::EllipticCurveType curve;
+ std::string pub_x_hex_str;
+ std::string pub_y_hex_str;
+ std::string priv_hex_str;
+
+ // PEM format
+ std::string pub_pem;
+ std::string priv_pem;
+};
+
+static const auto *kEcKeyTestVectors = new std::vector<EcKeyTestVector>({
+ // NIST P256
+ {
+ /*.curve=*/subtle::NIST_P256,
+ /*.pub_x_hex_str=*/
+ "1455cfd594d44df125f1ff643636740c6cc59972091fee6fa9b8d3897d59b0e0",
+ /*.pub_y_hex_str=*/
+ "d0b655238d8c0cebbfde77b1fda62ad19ccc6bf25a4ebf5637d3597983094363",
+ /*.priv_hex_str=*/
+ "8485FB768E109D14BE1E219D4D806523308E0E401DB1DE95DC938E8903C49B2C",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFFXP1ZTUTfEl8f9kNjZ0DGzFmXIJ
+H+5vqbjTiX1ZsODQtlUjjYwM67/ed7H9pirRnMxr8lpOv1Y301l5gwlDYw==
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIISF+3aOEJ0Uvh4hnU2AZSMwjg5AHbHeldyTjokDxJssoAoGCCqGSM49
+AwEHoUQDQgAEFFXP1ZTUTfEl8f9kNjZ0DGzFmXIJH+5vqbjTiX1ZsODQtlUjjYwM
+67/ed7H9pirRnMxr8lpOv1Y301l5gwlDYw==
+-----END EC PRIVATE KEY-----)",
+ },
+ {
+ /*.curve=*/subtle::NIST_P256,
+ /*.pub_x_hex_str=*/
+ "ee21893b340260360f1ae3d26bf0a066eadc8c63690b2f1de308220800d9d1ab",
+ /*.pub_y_hex_str=*/
+ "d334a5917d2be49475af2454feea41d4418ea99eec791d1a0cc1c2890f8b33ee",
+ /*.priv_hex_str=*/
+ "cac853f79a95c7d8697d0469ccda4faf940d80d1e0c81ffa0e6082ed9a85654b",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7iGJOzQCYDYPGuPSa/CgZurcjGNp
+Cy8d4wgiCADZ0avTNKWRfSvklHWvJFT+6kHUQY6pnux5HRoMwcKJD4sz7g==
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMrIU/ealcfYaX0EaczaT6+UDYDR4Mgf+g5ggu2ahWVLoAoGCCqGSM49
+AwEHoUQDQgAE7iGJOzQCYDYPGuPSa/CgZurcjGNpCy8d4wgiCADZ0avTNKWRfSvk
+lHWvJFT+6kHUQY6pnux5HRoMwcKJD4sz7g==
+-----END EC PRIVATE KEY-----)",
+ },
+
+ // NIST P384
+ {
+ /*.curve=*/subtle::NIST_P384,
+ /*.pub_x_hex_str=*/
+ "49b1a78537281c81984e00092f04c22c610cac2aba7a3de992bf6ad22305d2d5450187"
+ "57ed823c643334e18d95b2e642",
+ /*.pub_y_hex_str=*/
+ "d2a851445c5da0bf0d543eaad5ff98634483c549d96045243121ed6d5c9ba64dab656a"
+ "6d25e018b01c4d3ab3f1738989",
+ /*.priv_hex_str=*/
+ "0254cd5840eec13b0d68ba08fdbc147c22906046ecb2fca2625294be74dea29aa370fd"
+ "830985d278099644ecf89167cd",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAESbGnhTcoHIGYTgAJLwTCLGEMrCq6ej3p
+kr9q0iMF0tVFAYdX7YI8ZDM04Y2VsuZC0qhRRFxdoL8NVD6q1f+YY0SDxUnZYEUk
+MSHtbVybpk2rZWptJeAYsBxNOrPxc4mJ
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDACVM1YQO7BOw1ougj9vBR8IpBgRuyy/KJiUpS+dN6imqNw/YMJhdJ4
+CZZE7PiRZ82gBwYFK4EEACKhZANiAARJsaeFNygcgZhOAAkvBMIsYQysKrp6PemS
+v2rSIwXS1UUBh1ftgjxkMzThjZWy5kLSqFFEXF2gvw1UPqrV/5hjRIPFSdlgRSQx
+Ie1tXJumTatlam0l4BiwHE06s/FziYk=
+-----END EC PRIVATE KEY-----)",
+ },
+ {
+ /*.curve=*/subtle::NIST_P384,
+ /*.pub_x_hex_str=*/
+ "82de2530a8d589149c8a60fdd529ed7a465db62d7412771a7ec40a69be139226b60906"
+ "cc784007d8e28a79dca528e66c",
+ /*.pub_y_hex_str=*/
+ "c41f7532b8325aad3f1dddebddb702ebe70259bb5730e6bc4a75baec0d85c52d0d00c8"
+ "e372d1da0d1ca10136e4cfd262",
+ /*.priv_hex_str=*/
+ "a6a8415b526418966758cfda45c19b4fe0ac4cf06d301b195ffea231d0eda67a54fb7c"
+ "bc12470296e29e86359de53aee",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgt4lMKjViRScimD91SntekZdti10Enca
+fsQKab4Tkia2CQbMeEAH2OKKedylKOZsxB91MrgyWq0/Hd3r3bcC6+cCWbtXMOa8
+SnW67A2FxS0NAMjjctHaDRyhATbkz9Ji
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCmqEFbUmQYlmdYz9pFwZtP4KxM8G0wGxlf/qIx0O2melT7fLwSRwKW
+4p6GNZ3lOu6gBwYFK4EEACKhZANiAASC3iUwqNWJFJyKYP3VKe16Rl22LXQSdxp+
+xAppvhOSJrYJBsx4QAfY4op53KUo5mzEH3UyuDJarT8d3evdtwLr5wJZu1cw5rxK
+dbrsDYXFLQ0AyONy0doNHKEBNuTP0mI=
+-----END EC PRIVATE KEY-----)",
+ },
+
+ // NIST P521
+ {
+ /*.curve=*/subtle::NIST_P521,
+ /*.pub_x_hex_str=*/
+ "01d09ee2f33ce601d8594b09e668e128a7708ce752ef589d1a2c405523db0b68a0cb58"
+ "60359b12c5371fc462f4142339ca7ff2550833f0a64887951ddb64e7d139d5",
+ /*.pub_y_hex_str=*/
+ "01b45ce12804afcf17fbd60728d362d4787b750d561e52144fd517807ddaa2b396bed9"
+ "98227a5696d9c997a1cf0b6f1a3724ce25c7396dc2ea62c4bdf467061916e3",
+ /*.priv_hex_str=*/
+ "01f1913a921271c06686482a51dbf2c853aefbcc62b2b23d473a4c818d570e55566742"
+ "edd9f05d0532f73d40c11d3d31c3734e4470cc0491ad911a209f1e88dcd712",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB0J7i8zzmAdhZSwnmaOEop3CM51Lv
+WJ0aLEBVI9sLaKDLWGA1mxLFNx/EYvQUIznKf/JVCDPwpkiHlR3bZOfROdUBtFzh
+KASvzxf71gco02LUeHt1DVYeUhRP1ReAfdqis5a+2ZgielaW2cmXoc8Lbxo3JM4l
+xzltwupixL30ZwYZFuM=
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIB8ZE6khJxwGaGSCpR2/LIU677zGKysj1HOkyBjVcOVVZnQu3Z8F0F
+Mvc9QMEdPTHDc05EcMwEka2RGiCfHojc1xKgBwYFK4EEACOhgYkDgYYABAHQnuLz
+POYB2FlLCeZo4SincIznUu9YnRosQFUj2wtooMtYYDWbEsU3H8Ri9BQjOcp/8lUI
+M/CmSIeVHdtk59E51QG0XOEoBK/PF/vWByjTYtR4e3UNVh5SFE/VF4B92qKzlr7Z
+mCJ6VpbZyZehzwtvGjckziXHOW3C6mLEvfRnBhkW4w==
+-----END EC PRIVATE KEY-----)",
+ },
+ {
+ /*.curve=*/subtle::NIST_P521,
+ /*.pub_x_hex_str=*/
+ "0108803f92f8449fdfca02c8c2b49643f407f63dda728ad38e3598b887b5831ab063d9"
+ "60c5fd321ee597f4273fc0596015ce406515a2ab24a7c96a44802d74c3ac7b",
+ /*.pub_y_hex_str=*/
+ "01f216dc0f590b920d9c026e0aedc2b1cfe85d4f2d607db632395c7f64c05328593633"
+ "635b6ad8bf51d2ee70c88000e96fd340601211c1d1eb0b32773806506b47b0",
+ /*.priv_hex_str=*/
+ "0010a207e650cf531c98c0c6d1cfdb88a5ee57f02734cbab93b8ae30d9dac0845d1761"
+ "9be33f9aeaeab35401e63a149a87ae45b45bf2fea125d96c5d418d96bcda85",
+ /*.pub_pem=*/R"(-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBCIA/kvhEn9/KAsjCtJZD9Af2Pdpy
+itOONZi4h7WDGrBj2WDF/TIe5Zf0Jz/AWWAVzkBlFaKrJKfJakSALXTDrHsB8hbc
+D1kLkg2cAm4K7cKxz+hdTy1gfbYyOVx/ZMBTKFk2M2Nbati/UdLucMiAAOlv00Bg
+EhHB0esLMnc4BlBrR7A=
+-----END PUBLIC KEY-----)",
+ /*.priv_pem=*/R"(-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIAEKIH5lDPUxyYwMbRz9uIpe5X8Cc0y6uTuK4w2drAhF0XYZvjP5rq
+6rNUAeY6FJqHrkW0W/L+oSXZbF1BjZa82oWgBwYFK4EEACOhgYkDgYYABAEIgD+S
++ESf38oCyMK0lkP0B/Y92nKK0441mLiHtYMasGPZYMX9Mh7ll/QnP8BZYBXOQGUV
+oqskp8lqRIAtdMOsewHyFtwPWQuSDZwCbgrtwrHP6F1PLWB9tjI5XH9kwFMoWTYz
+Y1tq2L9R0u5wyIAA6W/TQGASEcHR6wsydzgGUGtHsA==
+-----END EC PRIVATE KEY-----)",
+ },
+});
+
class PemParserTest : public ::testing::Test {
public:
PemParserTest() : rsa_(RSA_new()) {}
@@ -129,26 +303,26 @@
SubtleUtilBoringSSL::bn2str(e_bn, BN_num_bytes(e_bn)).ValueOrDie());
EXPECT_EQ(key->n,
SubtleUtilBoringSSL::bn2str(n_bn, BN_num_bytes(n_bn)).ValueOrDie());
- EXPECT_EQ(key->d,
+ EXPECT_EQ(util::SecretDataAsStringView(key->d),
SubtleUtilBoringSSL::bn2str(d_bn, BN_num_bytes(d_bn)).ValueOrDie());
// Verify private key factors.
const BIGNUM *p_bn, *q_bn;
RSA_get0_factors(rsa_.get(), &p_bn, &q_bn);
- EXPECT_EQ(key->p,
+ EXPECT_EQ(util::SecretDataAsStringView(key->p),
SubtleUtilBoringSSL::bn2str(p_bn, BN_num_bytes(p_bn)).ValueOrDie());
- EXPECT_EQ(key->q,
+ EXPECT_EQ(util::SecretDataAsStringView(key->q),
SubtleUtilBoringSSL::bn2str(q_bn, BN_num_bytes(q_bn)).ValueOrDie());
// Verify CRT parameters.
const BIGNUM *dp_bn, *dq_bn, *crt_bn;
RSA_get0_crt_params(rsa_.get(), &dp_bn, &dq_bn, &crt_bn);
EXPECT_EQ(
- key->dp,
+ util::SecretDataAsStringView(key->dp),
SubtleUtilBoringSSL::bn2str(dp_bn, BN_num_bytes(dp_bn)).ValueOrDie());
EXPECT_EQ(
- key->dq,
+ util::SecretDataAsStringView(key->dq),
SubtleUtilBoringSSL::bn2str(dq_bn, BN_num_bytes(dq_bn)).ValueOrDie());
EXPECT_EQ(
- key->crt,
+ util::SecretDataAsStringView(key->crt),
SubtleUtilBoringSSL::bn2str(crt_bn, BN_num_bytes(crt_bn)).ValueOrDie());
}
@@ -168,6 +342,73 @@
.ok());
}
+TEST_F(PemParserTest, WriteEcPublicKeySucceeds) {
+ for (const auto& test_vector : *kEcKeyTestVectors) {
+ // Load an EcKey with the test vector.
+ SubtleUtilBoringSSL::EcKey ec_key;
+ ec_key.curve = test_vector.curve;
+ ec_key.pub_x = absl::HexStringToBytes(test_vector.pub_x_hex_str);
+ ec_key.pub_y = absl::HexStringToBytes(test_vector.pub_y_hex_str);
+ ec_key.priv = util::SecretDataFromStringView(
+ absl::HexStringToBytes(test_vector.priv_hex_str));
+
+ // Check that converting the public key with WriteEcPublicKey() succeeds.
+ auto pem_material_statusor = PemParser::WriteEcPublicKey(ec_key);
+ ASSERT_TRUE(pem_material_statusor.ok()) << pem_material_statusor.status();
+ std::string pem_material = pem_material_statusor.ValueOrDie();
+ EXPECT_TRUE(absl::StripAsciiWhitespace(pem_material) ==
+ absl::StripAsciiWhitespace(test_vector.pub_pem));
+ }
+}
+
+TEST_F(PemParserTest, WriteEcPrivateKeySucceeds) {
+ for (const auto& test_vector : *kEcKeyTestVectors) {
+ // Load an EcKey with the test vector.
+ SubtleUtilBoringSSL::EcKey ec_key;
+ ec_key.curve = test_vector.curve;
+ ec_key.pub_x = absl::HexStringToBytes(test_vector.pub_x_hex_str);
+ ec_key.pub_y = absl::HexStringToBytes(test_vector.pub_y_hex_str);
+ ec_key.priv = util::SecretDataFromStringView(
+ absl::HexStringToBytes(test_vector.priv_hex_str));
+
+ // Check that converting the private key with WriteEcPrivateKey() succeeds.
+ auto pem_material_statusor = PemParser::WriteEcPrivateKey(ec_key);
+ ASSERT_TRUE(pem_material_statusor.ok()) << pem_material_statusor.status();
+ std::string pem_material = pem_material_statusor.ValueOrDie();
+ EXPECT_TRUE(absl::StripAsciiWhitespace(pem_material) ==
+ absl::StripAsciiWhitespace(test_vector.priv_pem));
+ }
+}
+
+TEST_F(PemParserTest, WriteEcPublicKeyWithBadXFails) {
+ auto ec_key_statusor = SubtleUtilBoringSSL::GetNewEcKey(subtle::NIST_P256);
+ ASSERT_TRUE(ec_key_statusor.ok()) << ec_key_statusor.status();
+ SubtleUtilBoringSSL::EcKey ec_key = ec_key_statusor.ValueOrDie();
+ Corrupt(&ec_key.pub_x);
+ EXPECT_THAT(PemParser::WriteEcPublicKey(ec_key).status(),
+ StatusIs(util::error::INVALID_ARGUMENT));
+}
+
+TEST_F(PemParserTest, WriteEcPublicKeyWithBadYFails) {
+ auto ec_key_statusor = SubtleUtilBoringSSL::GetNewEcKey(subtle::NIST_P256);
+ ASSERT_TRUE(ec_key_statusor.ok()) << ec_key_statusor.status();
+ SubtleUtilBoringSSL::EcKey ec_key = ec_key_statusor.ValueOrDie();
+ Corrupt(&ec_key.pub_y);
+ EXPECT_THAT(PemParser::WriteEcPublicKey(ec_key).status(),
+ StatusIs(util::error::INVALID_ARGUMENT));
+}
+
+TEST_F(PemParserTest, WriteEcPrivateKeyWithBadPrivFails) {
+ auto ec_key_statusor = SubtleUtilBoringSSL::GetNewEcKey(subtle::NIST_P256);
+ ASSERT_TRUE(ec_key_statusor.ok()) << ec_key_statusor.status();
+ SubtleUtilBoringSSL::EcKey ec_key = ec_key_statusor.ValueOrDie();
+ std::string priv = std::string(util::SecretDataAsStringView(ec_key.priv));
+ Corrupt(&priv);
+ ec_key.priv = util::SecretDataFromStringView(priv);
+ EXPECT_THAT(PemParser::WriteEcPrivateKey(ec_key).status(),
+ StatusIs(util::error::INVALID_ARGUMENT));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/subtle/rsa_ssa_pkcs1_sign_boringssl.cc b/cc/subtle/rsa_ssa_pkcs1_sign_boringssl.cc
index c10ea1b..2b22438 100644
--- a/cc/subtle/rsa_ssa_pkcs1_sign_boringssl.cc
+++ b/cc/subtle/rsa_ssa_pkcs1_sign_boringssl.cc
@@ -18,6 +18,7 @@
#include <vector>
+#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "openssl/base.h"
#include "openssl/digest.h"
@@ -73,8 +74,8 @@
SubtleUtilBoringSSL::GetErrors()));
}
- return std::unique_ptr<PublicKeySign>(
- new RsaSsaPkcs1SignBoringSsl(std::move(rsa), sig_hash.ValueOrDie()));
+ return {absl::WrapUnique(
+ new RsaSsaPkcs1SignBoringSsl(std::move(rsa), sig_hash.ValueOrDie()))};
}
util::StatusOr<std::string> RsaSsaPkcs1SignBoringSsl::Sign(
diff --git a/cc/subtle/rsa_ssa_pss_sign_boringssl.cc b/cc/subtle/rsa_ssa_pss_sign_boringssl.cc
index 0253083..13045f2 100644
--- a/cc/subtle/rsa_ssa_pss_sign_boringssl.cc
+++ b/cc/subtle/rsa_ssa_pss_sign_boringssl.cc
@@ -18,6 +18,7 @@
#include <vector>
+#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "openssl/base.h"
#include "openssl/evp.h"
@@ -72,9 +73,9 @@
SubtleUtilBoringSSL::GetErrors()));
}
- return std::unique_ptr<PublicKeySign>(
+ return {absl::WrapUnique(
new RsaSsaPssSignBoringSsl(std::move(rsa), sig_hash.ValueOrDie(),
- mgf1_hash.ValueOrDie(), params.salt_length));
+ mgf1_hash.ValueOrDie(), params.salt_length))};
}
RsaSsaPssSignBoringSsl::RsaSsaPssSignBoringSsl(bssl::UniquePtr<RSA> private_key,
diff --git a/cc/subtle/subtle_util_boringssl.cc b/cc/subtle/subtle_util_boringssl.cc
index 157a73d..fb7c97d 100644
--- a/cc/subtle/subtle_util_boringssl.cc
+++ b/cc/subtle/subtle_util_boringssl.cc
@@ -16,6 +16,9 @@
#include "tink/subtle/subtle_util_boringssl.h"
+#include <algorithm>
+#include <iterator>
+
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
@@ -28,8 +31,10 @@
#include "openssl/err.h"
#include "openssl/mem.h"
#include "openssl/rsa.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/common_enums.h"
#include "tink/util/errors.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
namespace crypto {
@@ -165,11 +170,12 @@
return pub_y_str.status();
}
ec_key.pub_y = pub_y_str.ValueOrDie();
- auto priv_key_str = bn2str(priv_key, ScalarSizeInBytes(group.get()));
- if (!priv_key_str.ok()) {
- return priv_key_str.status();
+ auto priv_key_or =
+ BignumToSecretData(priv_key, ScalarSizeInBytes(group.get()));
+ if (!priv_key_or.ok()) {
+ return priv_key_or.status();
}
- ec_key.priv = priv_key_str.ValueOrDie();
+ ec_key.priv = priv_key_or.ValueOrDie();
return ec_key;
}
@@ -191,9 +197,8 @@
ec_key.pub_x =
std::string(reinterpret_cast<const char *>(x25519_key->public_value),
X25519_PUBLIC_VALUE_LEN);
- ec_key.priv =
- std::string(reinterpret_cast<const char *>(x25519_key->private_key),
- X25519_PRIVATE_KEY_LEN);
+ ec_key.priv = util::SecretData(std::begin(x25519_key->private_key),
+ std::end(x25519_key->private_key));
return ec_key;
}
@@ -211,10 +216,10 @@
"Invalid X25519 key. pub_y is unexpectedly set.");
}
// Curve25519 public key is x, not (x,y).
- ec_key.pub_x.copy(reinterpret_cast<char *>(x25519_key->public_value),
- X25519_PUBLIC_VALUE_LEN);
- ec_key.priv.copy(reinterpret_cast<char *>(x25519_key->private_key),
- X25519_PRIVATE_KEY_LEN);
+ std::copy_n(ec_key.pub_x.begin(), X25519_PUBLIC_VALUE_LEN,
+ std::begin(x25519_key->public_value));
+ std::copy_n(ec_key.priv.begin(), X25519_PRIVATE_KEY_LEN,
+ std::begin(x25519_key->private_key));
return std::move(x25519_key);
}
@@ -506,11 +511,22 @@
// static
util::Status SubtleUtilBoringSSL::ValidateRsaModulusSize(size_t modulus_size) {
if (modulus_size < 2048) {
- return ToStatusF(
+ return util::Status(
util::error::INVALID_ARGUMENT,
- "Modulus size is %u; only modulus size >= 2048-bit is supported",
- modulus_size);
+ absl::StrCat("Modulus size is ", modulus_size,
+ " only modulus size >= 2048-bit is supported"));
}
+
+ // In FIPS only mode we check here if the modulus is 3072, as this is the
+ // only size which is covered by the FIPS validation and supported by Tink.
+ // See
+ // https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3318
+ if (kUseOnlyFips && (modulus_size != 3072)) {
+ return util::Status(util::error::INTERNAL,
+ absl::StrCat("Modulus size is ", modulus_size,
+ " only modulus size 3072 is supported "));
+ }
+
return util::Status::OK;
}
@@ -560,7 +576,7 @@
// Save exponents.
auto n_str = bn2str(n_bn, BN_num_bytes(n_bn));
auto e_str = bn2str(e_bn, BN_num_bytes(e_bn));
- auto d_str = bn2str(d_bn, BN_num_bytes(d_bn));
+ auto d_str = BignumToSecretData(d_bn, BN_num_bytes(d_bn));
if (!n_str.ok()) return n_str.status();
if (!e_str.ok()) return e_str.status();
if (!d_str.ok()) return d_str.status();
@@ -574,8 +590,8 @@
// Save factors.
const BIGNUM *p_bn, *q_bn;
RSA_get0_factors(rsa.get(), &p_bn, &q_bn);
- auto p_str = bn2str(p_bn, BN_num_bytes(p_bn));
- auto q_str = bn2str(q_bn, BN_num_bytes(q_bn));
+ auto p_str = BignumToSecretData(p_bn, BN_num_bytes(p_bn));
+ auto q_str = BignumToSecretData(q_bn, BN_num_bytes(q_bn));
if (!p_str.ok()) return p_str.status();
if (!q_str.ok()) return q_str.status();
private_key->p = std::move(p_str.ValueOrDie());
@@ -584,9 +600,9 @@
// Save CRT parameters.
const BIGNUM *dp_bn, *dq_bn, *crt_bn;
RSA_get0_crt_params(rsa.get(), &dp_bn, &dq_bn, &crt_bn);
- auto dp_str = bn2str(dp_bn, BN_num_bytes(dp_bn));
- auto dq_str = bn2str(dq_bn, BN_num_bytes(dq_bn));
- auto crt_str = bn2str(crt_bn, BN_num_bytes(crt_bn));
+ auto dp_str = BignumToSecretData(dp_bn, BN_num_bytes(dp_bn));
+ auto dq_str = BignumToSecretData(dq_bn, BN_num_bytes(dq_bn));
+ auto crt_str = BignumToSecretData(crt_bn, BN_num_bytes(crt_bn));
if (!dp_str.ok()) return dp_str.status();
if (!dq_str.ok()) return dq_str.status();
if (!crt_str.ok()) return crt_str.status();
@@ -602,7 +618,7 @@
const SubtleUtilBoringSSL::RsaPrivateKey &key, RSA *rsa) {
auto n = SubtleUtilBoringSSL::str2bn(key.n);
auto e = SubtleUtilBoringSSL::str2bn(key.e);
- auto d = SubtleUtilBoringSSL::str2bn(key.d);
+ auto d = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.d));
if (!n.ok()) return n.status();
if (!e.ok()) return e.status();
if (!d.ok()) return d.status();
@@ -622,8 +638,8 @@
// static
util::Status SubtleUtilBoringSSL::CopyPrimeFactors(
const SubtleUtilBoringSSL::RsaPrivateKey &key, RSA *rsa) {
- auto p = SubtleUtilBoringSSL::str2bn(key.p);
- auto q = SubtleUtilBoringSSL::str2bn(key.q);
+ auto p = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.p));
+ auto q = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.q));
if (!p.ok()) return p.status();
if (!q.ok()) return q.status();
if (RSA_set0_factors(rsa, p.ValueOrDie().get(), q.ValueOrDie().get()) != 1) {
@@ -639,9 +655,9 @@
// static
util::Status SubtleUtilBoringSSL::CopyCrtParams(
const SubtleUtilBoringSSL::RsaPrivateKey &key, RSA *rsa) {
- auto dp = SubtleUtilBoringSSL::str2bn(key.dp);
- auto dq = SubtleUtilBoringSSL::str2bn(key.dq);
- auto crt = SubtleUtilBoringSSL::str2bn(key.crt);
+ auto dp = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.dp));
+ auto dq = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.dq));
+ auto crt = SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(key.crt));
if (!dp.ok()) return dp.status();
if (!dq.ok()) return dq.status();
if (!crt.ok()) return crt.status();
diff --git a/cc/subtle/subtle_util_boringssl.h b/cc/subtle/subtle_util_boringssl.h
index 4c87428..360c58e 100644
--- a/cc/subtle/subtle_util_boringssl.h
+++ b/cc/subtle/subtle_util_boringssl.h
@@ -41,7 +41,7 @@
EllipticCurveType curve;
std::string pub_x; // affine coordinates in bigendian representation
std::string pub_y;
- std::string priv; // big integer in bigendian representation
+ util::SecretData priv; // big integer in bigendian representation
};
struct X25519Key {
@@ -94,22 +94,22 @@
std::string e;
// Private exponent.
// Unsigned big integer in bigendian representation.
- std::string d;
+ util::SecretData d;
// The prime factor p of n.
// Unsigned big integer in bigendian representation.
- std::string p;
+ util::SecretData p;
// The prime factor q of n.
// Unsigned big integer in bigendian representation.
- std::string q;
+ util::SecretData q;
// d mod (p - 1).
- std::string dp;
+ util::SecretData dp;
// d mod (q - 1).
// Unsigned big integer in bigendian representation.
- std::string dq;
+ util::SecretData dq;
// Chinese Remainder Theorem coefficient q^(-1) mod p.
// Unsigned big integer in bigendian representation.
- std::string crt;
+ util::SecretData crt;
};
// Returns BoringSSL's BIGNUM constructed from bigendian string
diff --git a/cc/subtle/subtle_util_boringssl_test.cc b/cc/subtle/subtle_util_boringssl_test.cc
index 142502e..e439238 100644
--- a/cc/subtle/subtle_util_boringssl_test.cc
+++ b/cc/subtle/subtle_util_boringssl_test.cc
@@ -33,6 +33,7 @@
#include "tink/subtle/common_enums.h"
#include "tink/subtle/ec_util.h"
#include "tink/subtle/wycheproof_util.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
@@ -327,11 +328,21 @@
&public_key),
IsOk());
auto n = std::move(SubtleUtilBoringSSL::str2bn(private_key.n).ValueOrDie());
- auto d = std::move(SubtleUtilBoringSSL::str2bn(private_key.d).ValueOrDie());
- auto p = std::move(SubtleUtilBoringSSL::str2bn(private_key.p).ValueOrDie());
- auto q = std::move(SubtleUtilBoringSSL::str2bn(private_key.q).ValueOrDie());
- auto dp = std::move(SubtleUtilBoringSSL::str2bn(private_key.dp).ValueOrDie());
- auto dq = std::move(SubtleUtilBoringSSL::str2bn(private_key.dq).ValueOrDie());
+ auto d = std::move(
+ SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(private_key.d))
+ .ValueOrDie());
+ auto p = std::move(
+ SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(private_key.p))
+ .ValueOrDie());
+ auto q = std::move(
+ SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(private_key.q))
+ .ValueOrDie());
+ auto dp = std::move(
+ SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(private_key.dp))
+ .ValueOrDie());
+ auto dq = std::move(
+ SubtleUtilBoringSSL::str2bn(util::SecretDataAsStringView(private_key.dq))
+ .ValueOrDie());
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
// Check n = p * q.
@@ -440,7 +451,7 @@
EXPECT_EQ(ec_key.curve, EllipticCurveType::CURVE25519);
EXPECT_EQ(ec_key.pub_x.length(), X25519_PUBLIC_VALUE_LEN);
EXPECT_TRUE(ec_key.pub_y.empty());
- EXPECT_EQ(ec_key.priv.length(), X25519_PRIVATE_KEY_LEN);
+ EXPECT_EQ(ec_key.priv.size(), X25519_PRIVATE_KEY_LEN);
}
TEST(CreateNewX25519KeyTest, GeneratesDifferentKeysEveryTime) {
diff --git a/cc/subtle/xchacha20_poly1305_boringssl.cc b/cc/subtle/xchacha20_poly1305_boringssl.cc
index 28c892d..ac7f11f 100644
--- a/cc/subtle/xchacha20_poly1305_boringssl.cc
+++ b/cc/subtle/xchacha20_poly1305_boringssl.cc
@@ -23,6 +23,7 @@
#include "openssl/err.h"
#include "openssl/evp.h"
#include "tink/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
@@ -42,6 +43,9 @@
util::StatusOr<std::unique_ptr<Aead>> XChacha20Poly1305BoringSsl::New(
util::SecretData key) {
+ auto status = CheckFipsCompatibility<XChacha20Poly1305BoringSsl>();
+ if (!status.ok()) return status;
+
if (!IsValidKeySize(key.size())) {
return util::Status(util::error::INVALID_ARGUMENT, "Invalid key size");
}
diff --git a/cc/subtle/xchacha20_poly1305_boringssl.h b/cc/subtle/xchacha20_poly1305_boringssl.h
index c603633..ab6272c 100644
--- a/cc/subtle/xchacha20_poly1305_boringssl.h
+++ b/cc/subtle/xchacha20_poly1305_boringssl.h
@@ -23,6 +23,7 @@
#include "absl/strings/string_view.h"
#include "openssl/base.h"
#include "tink/aead.h"
+#include "tink/config/tink_fips.h"
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
@@ -48,6 +49,9 @@
absl::string_view ciphertext,
absl::string_view additional_data) const override;
+ static constexpr crypto::tink::FipsCompatibility kFipsStatus =
+ crypto::tink::FipsCompatibility::kNotFips;
+
private:
// The following constants are in bytes.
static constexpr int kNonceSize = 24;
diff --git a/cc/subtle/xchacha20_poly1305_boringssl_test.cc b/cc/subtle/xchacha20_poly1305_boringssl_test.cc
index 76dcee1..5ec9341 100644
--- a/cc/subtle/xchacha20_poly1305_boringssl_test.cc
+++ b/cc/subtle/xchacha20_poly1305_boringssl_test.cc
@@ -24,6 +24,7 @@
#include "openssl/err.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
@@ -31,7 +32,13 @@
namespace subtle {
namespace {
-TEST(XChacha20Poly1305BoringSslTest, testBasic) {
+using ::crypto::tink::test::StatusIs;
+
+TEST(XChacha20Poly1305BoringSslTest, TestBasic) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
auto res = XChacha20Poly1305BoringSsl::New(key);
@@ -48,7 +55,11 @@
EXPECT_EQ(pt.ValueOrDie(), message);
}
-TEST(XChacha20Poly1305BoringSslTest, testModification) {
+TEST(XChacha20Poly1305BoringSslTest, TestModification) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
auto cipher = std::move(XChacha20Poly1305BoringSsl::New(key).ValueOrDie());
@@ -78,6 +89,10 @@
void TestDecryptWithEmptyAad(crypto::tink::Aead* cipher, absl::string_view ct,
absl::string_view message) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
{ // AAD is a null string_view.
const absl::string_view aad;
auto pt_or_status = cipher->Decrypt(ct, aad);
@@ -99,7 +114,11 @@
}
}
-TEST(XChacha20Poly1305BoringSslTest, testAadEmptyVersusNullStringView) {
+TEST(XChacha20Poly1305BoringSslTest, TestAadEmptyVersusNullStringView) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
const util::SecretData key =
util::SecretDataFromStringView(test::HexDecodeOrDie(
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
@@ -128,7 +147,11 @@
}
}
-TEST(XChacha20Poly1305BoringSslTest, testMessageEmptyVersusNullStringView) {
+TEST(XChacha20Poly1305BoringSslTest, TestMessageEmptyVersusNullStringView) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
const util::SecretData key =
util::SecretDataFromStringView(test::HexDecodeOrDie(
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
@@ -165,7 +188,11 @@
}
}
-TEST(XChacha20Poly1305BoringSslTest, testBothMessageAndAadEmpty) {
+TEST(XChacha20Poly1305BoringSslTest, TestBothMessageAndAadEmpty) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
const util::SecretData key =
util::SecretDataFromStringView(test::HexDecodeOrDie(
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
@@ -203,7 +230,11 @@
}
}
-TEST(XChacha20Poly1305BoringSslTest, testInvalidKeySizes) {
+TEST(XChacha20Poly1305BoringSslTest, TestInvalidKeySizes) {
+ if (kUseOnlyFips) {
+ GTEST_SKIP() << "Not supported in FIPS-only mode";
+ }
+
for (int keysize = 0; keysize < 65; keysize++) {
if (keysize == 32) {
continue;
@@ -214,6 +245,18 @@
}
}
+TEST(XChacha20Poly1305BoringSslTest, TestFipsOnly) {
+ if (!kUseOnlyFips) {
+ GTEST_SKIP() << "Only supported in FIPS-only mode";
+ }
+
+ util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
+ "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
+
+ auto xchacha20_poly1305_res = subtle::XChacha20Poly1305BoringSsl::New(key256);
+ EXPECT_THAT(xchacha20_poly1305_res.status(), StatusIs(util::error::INTERNAL));
+}
+
} // namespace
} // namespace subtle
} // namespace tink
diff --git a/cc/third_party/aws_c_common.BUILD.bazel b/cc/third_party/aws_c_common.BUILD.bazel
new file mode 100644
index 0000000..de42eef
--- /dev/null
+++ b/cc/third_party/aws_c_common.BUILD.bazel
@@ -0,0 +1,29 @@
+licenses(["notice"]) # Apache 2.0
+
+load("@tink_base//tools:common.bzl", "template_rule")
+
+cc_library(
+ name = "aws_c_common",
+ srcs = glob(["source/*.c"]) +
+ glob(["source/posix/*.c"]),
+ hdrs = [
+ "include/aws/common/config.h"
+ ] + glob([
+ "include/**/*.h",
+ "include/aws/common/**/*.inl"
+ ]),
+ includes = ["include/"],
+ visibility = ["//visibility:public"],
+)
+
+template_rule(
+ name = "config.h",
+ src = "include/aws/common/config.h.in",
+ out = "include/aws/common/config.h",
+ substitutions = {
+ "cmakedefine AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS": "undef AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS",
+ "cmakedefine AWS_HAVE_GCC_INLINE_ASM": "define AWS_HAVE_GCC_INLINE_ASM",
+ "cmakedefine AWS_HAVE_MSVC_MULX": "undef AWS_HAVE_MSVC_MULX",
+ "cmakedefine AWS_HAVE_EXECINFO": "define AWS_HAVE_EXECINFO",
+ },
+)
diff --git a/cc/third_party/aws_c_event_stream.BUILD.bazel b/cc/third_party/aws_c_event_stream.BUILD.bazel
new file mode 100644
index 0000000..8f37e56
--- /dev/null
+++ b/cc/third_party/aws_c_event_stream.BUILD.bazel
@@ -0,0 +1,19 @@
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "aws_c_event_stream",
+ srcs = glob([
+ "source/*.c",
+ ]),
+ hdrs = glob([
+ "include/**/*.h"
+ ]),
+ includes = [
+ "include/",
+ ],
+ deps = [
+ "@aws_c_common",
+ "@aws_checksums"
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/cc/third_party/aws_checksums.BUILD.bazel b/cc/third_party/aws_checksums.BUILD.bazel
new file mode 100644
index 0000000..25fc636
--- /dev/null
+++ b/cc/third_party/aws_checksums.BUILD.bazel
@@ -0,0 +1,22 @@
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "aws_checksums",
+ srcs = glob([
+ "source/intel/*.c",
+ "source/*.c",
+ ]),
+ hdrs = glob([
+ "include/**/*.h"
+ ]),
+ includes = [
+ "include/",
+ ],
+ copts = [
+ "-O2" # Note there is some issue with the assembly implementation and GCC, therefore this should always be compiled with -O (https://github.com/awslabs/aws-checksums/issues/8)
+ ],
+ deps = [
+ "@aws_c_common",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/cc/third_party/aws_sdk_cpp.BUILD.bazel b/cc/third_party/aws_sdk_cpp.BUILD.bazel
index 6428b86..4fb7c1e 100644
--- a/cc/third_party/aws_sdk_cpp.BUILD.bazel
+++ b/cc/third_party/aws_sdk_cpp.BUILD.bazel
@@ -29,6 +29,9 @@
"aws-cpp-sdk-core/source/utils/crypto/factory/**/*.cpp",
"aws-cpp-sdk-kms/include/**/*.h",
"aws-cpp-sdk-kms/source/**/*.cpp",
+ "aws-cpp-sdk-core/source/monitoring/*.cpp",
+ "aws-cpp-sdk-core/source/net/linux-shared/*.cpp",
+ "aws-cpp-sdk-core/source/utils/crypto/openssl/*.cpp",
]),
hdrs = [
"aws-cpp-sdk-core/include/aws/core/SDKConfig.h",
@@ -40,16 +43,20 @@
# These must be in sync with version of aws_cpp_sdk in WORKSPACE.
defines = [
"AWS_SDK_VERSION_MAJOR=1",
- "AWS_SDK_VERSION_MINOR=4",
- "AWS_SDK_VERSION_PATCH=80",
+ "AWS_SDK_VERSION_MINOR=7",
+ "AWS_SDK_VERSION_PATCH=345",
"ENABLE_CURL_CLIENT",
- "ENABLE_NO_ENCRYPTION",
+ "ENABLE_OPENSSL_ENCRYPTION", # This is needed for UUID generation
+ "OPENSSL_IS_BORINGSSL",
"PLATFORM_LINUX",
],
visibility = ["//visibility:public"],
strip_include_prefix = "aws-cpp-sdk-core/include",
deps = [
+ "@aws_c_common",
+ "@aws_c_event_stream",
"@curl",
+ "@boringssl//:crypto",
],
)
diff --git a/cc/tink_cc_deps.bzl b/cc/tink_cc_deps.bzl
index fb8c1ea..9404a86 100644
--- a/cc/tink_cc_deps.bzl
+++ b/cc/tink_cc_deps.bzl
@@ -19,12 +19,12 @@
)
if not native.existing_rule("boring_ssl"):
- # Commit from 2018-08-16
+ # Commit from 2020-06-23
http_archive(
name = "boringssl",
- strip_prefix = "boringssl-18637c5f37b87e57ebde0c40fe19c1560ec88813",
- url = "https://github.com/google/boringssl/archive/18637c5f37b87e57ebde0c40fe19c1560ec88813.zip",
- sha256 = "bd923e59fca0d2b50db09af441d11c844c5e882a54c68943b7fc39a8cb5dd211",
+ strip_prefix = "boringssl-597b810379e126ae05d32c1d94b1a9464385acd0",
+ url = "https://github.com/google/boringssl/archive/597b810379e126ae05d32c1d94b1a9464385acd0.zip",
+ sha256 = "c4e8414cb36e62d2fee451296cc864f7ad1a4670396c8a67e1ee77ae84cc4167",
)
# GoogleTest/GoogleMock framework. Used by most C++ unit-tests.
@@ -48,15 +48,43 @@
)
if not native.existing_rule("aws_cpp_sdk"):
- # Release from 2018-07-04
+ # Release from 2020-06-01
http_archive(
name = "aws_cpp_sdk",
# Must be in sync with defines in third_party/aws_sdk_cpp.BUILD.bazel.
- url = "https://github.com/aws/aws-sdk-cpp/archive/1.4.80.tar.gz",
- strip_prefix = "aws-sdk-cpp-1.4.80",
+ url = "https://github.com/aws/aws-sdk-cpp/archive/1.7.345.tar.gz",
+ sha256 = "7df6491e6e0fac726c00b5e6298d5749b131b25a3dd8b905eb311dc7dcc97aaf",
+ strip_prefix = "aws-sdk-cpp-1.7.345",
build_file = "@tink_cc//:third_party/aws_sdk_cpp.BUILD.bazel",
)
+ if not native.existing_rule("aws_c_common"):
+ http_archive(
+ name = "aws_c_common",
+ url = "https://github.com/awslabs/aws-c-common/archive/v0.4.29.tar.gz",
+ sha256 = "01c2a58553a37b3aa5914d9e0bf7bf14507ff4937bc5872a678892ca20fcae1f",
+ strip_prefix = "aws-c-common-0.4.29",
+ build_file = "@tink_cc//:third_party/aws_c_common.BUILD.bazel",
+ )
+
+ if not native.existing_rule("aws_c_event_stream"):
+ http_archive(
+ name = "aws_c_event_stream",
+ url = "https://github.com/awslabs/aws-c-event-stream/archive/v0.1.4.tar.gz",
+ sha256 = "31d880d1c868d3f3df1e1f4b45e56ac73724a4dc3449d04d47fc0746f6f077b6",
+ strip_prefix = "aws-c-event-stream-0.1.4",
+ build_file = "@tink_cc//:third_party/aws_c_event_stream.BUILD.bazel",
+ )
+
+ if not native.existing_rule("aws_checksums"):
+ http_archive(
+ name = "aws_checksums",
+ url = "https://github.com/awslabs/aws-checksums/archive/v0.1.5.tar.gz",
+ sha256 = "6e6bed6f75cf54006b6bafb01b3b96df19605572131a2260fddaf0e87949ced0",
+ strip_prefix = "aws-checksums-0.1.5",
+ build_file = "@tink_cc//:third_party/aws_checksums.BUILD.bazel",
+ )
+
# gRPC needs rules_apple, which in turn needs rules_swift and apple_support
if not native.existing_rule("build_bazel_rules_apple"):
# Last commit available at 2020-04-28
diff --git a/cc/util/BUILD.bazel b/cc/util/BUILD.bazel
index 9cee0b2..7a371d6 100644
--- a/cc/util/BUILD.bazel
+++ b/cc/util/BUILD.bazel
@@ -78,6 +78,7 @@
visibility = ["//visibility:public"],
deps = [
"@com_google_absl//absl/base:core_headers",
+ "@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
],
)
@@ -192,6 +193,7 @@
":constants",
":enums",
":protobuf_helper",
+ ":secret_data",
":status",
":statusor",
"//:aead",
diff --git a/cc/util/CMakeLists.txt b/cc/util/CMakeLists.txt
index 4708a6f..5dab20b 100644
--- a/cc/util/CMakeLists.txt
+++ b/cc/util/CMakeLists.txt
@@ -50,6 +50,7 @@
status.h
DEPS
absl::base
+ absl::status
absl::strings
PUBLIC
)
@@ -180,6 +181,7 @@
tink::proto::tink_cc_proto
tink::proto::xchacha20_poly1305_cc_proto
tink::util::buffer
+ tink::util::secret_data
absl::core_headers
absl::memory
absl::strings
diff --git a/cc/util/errors_test.cc b/cc/util/errors_test.cc
index bd799c1..cd0a0de 100644
--- a/cc/util/errors_test.cc
+++ b/cc/util/errors_test.cc
@@ -14,10 +14,11 @@
//
///////////////////////////////////////////////////////////////////////////////
-#include "gtest/gtest.h"
#include "tink/util/errors.h"
+
+#include "gtest/gtest.h"
+#include "absl/status/status.h"
#include "tink/util/status.h"
-// placeholder_google3_status_header, please ignore
namespace crypto {
namespace tink {
@@ -41,7 +42,15 @@
EXPECT_EQ(crypto::tink::util::error::UNKNOWN, status.error_code());
}
-// placeholder_status_conversion_test, please ignore
+TEST(ErrorsTest, ToAbslStatus) {
+ crypto::tink::util::Status tink_status(util::error::INVALID_ARGUMENT,
+ "error");
+ ::absl::Status g3_status(tink_status);
+ EXPECT_FALSE(g3_status.ok());
+ EXPECT_EQ(g3_status.message(), "error");
+
+ EXPECT_EQ(::absl::Status(crypto::tink::util::OkStatus()), ::absl::OkStatus());
+}
} // namespace
} // namespace tink
diff --git a/cc/util/status.cc b/cc/util/status.cc
index a962449..c2ac339 100644
--- a/cc/util/status.cc
+++ b/cc/util/status.cc
@@ -19,7 +19,7 @@
#include "tink/util/status.h"
#include "absl/strings/str_cat.h"
-// placeholder_google3_status_header, please ignore
+#include "absl/status/status.h"
using ::std::ostream;
@@ -49,7 +49,17 @@
} // namespace
-// placeholder_implicit_type_conversion, please ignore
+Status::Status(const ::absl::Status& status)
+ : code_(::crypto::tink::util::error::OK) {
+ if (status.ok()) return;
+ code_ = static_cast<::crypto::tink::util::error::Code>(status.code());
+ message_ = std::string(status.message());
+}
+
+Status::operator ::absl::Status() const {
+ if (ok()) return ::absl::OkStatus();
+ return ::absl::Status(static_cast<absl::StatusCode>(code_), message_);
+}
Status::Status() : code_(::crypto::tink::util::error::OK), message_("") {
}
diff --git a/cc/util/status.h b/cc/util/status.h
index 70aee58..746912b 100644
--- a/cc/util/status.h
+++ b/cc/util/status.h
@@ -23,8 +23,7 @@
#include <string>
#include "absl/base/attributes.h"
-
-// placeholder_forward_declaration, please ignore
+#include "absl/status/status.h"
namespace crypto {
namespace tink {
@@ -171,7 +170,8 @@
std::string ToString() const;
- // placeholder_implicit_type_conversion, please ignore
+ Status(const ::absl::Status& status);
+ operator ::absl::Status() const;
private:
::crypto::tink::util::error::Code code_;
diff --git a/cc/util/test_util.cc b/cc/util/test_util.cc
index 6273b13..c45c4ad 100644
--- a/cc/util/test_util.cc
+++ b/cc/util/test_util.cc
@@ -38,6 +38,7 @@
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/enums.h"
#include "tink/util/protobuf_helper.h"
+#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "proto/aes_ctr_hmac_aead.pb.h"
@@ -265,7 +266,8 @@
Enums::ProtoToSubtle(curve_type)).ValueOrDie();
EciesAeadHkdfPrivateKey ecies_key;
ecies_key.set_version(0);
- ecies_key.set_key_value(test_key.priv);
+ ecies_key.set_key_value(
+ std::string(util::SecretDataAsStringView(test_key.priv)));
auto public_key = ecies_key.mutable_public_key();
public_key->set_version(0);
public_key->set_x(test_key.pub_x);
@@ -362,7 +364,8 @@
Enums::ProtoToSubtle(curve_type)).ValueOrDie();
EcdsaPrivateKey ecdsa_key;
ecdsa_key.set_version(0);
- ecdsa_key.set_key_value(test_key.priv);
+ ecdsa_key.set_key_value(
+ std::string(util::SecretDataAsStringView(test_key.priv)));
auto public_key = ecdsa_key.mutable_public_key();
public_key->set_version(0);
public_key->set_x(test_key.pub_x);
diff --git a/cmake/TinkWorkspace.cmake b/cmake/TinkWorkspace.cmake
index 6edb2c7..8e589b7 100644
--- a/cmake/TinkWorkspace.cmake
+++ b/cmake/TinkWorkspace.cmake
@@ -61,8 +61,8 @@
http_archive(
NAME boringssl
- URL https://github.com/google/boringssl/archive/18637c5f37b87e57ebde0c40fe19c1560ec88813.zip
- SHA256 bd923e59fca0d2b50db09af441d11c844c5e882a54c68943b7fc39a8cb5dd211
+ URL https://github.com/google/boringssl/archive/597b810379e126ae05d32c1d94b1a9464385acd0.zip
+ SHA256 c4e8414cb36e62d2fee451296cc864f7ad1a4670396c8a67e1ee77ae84cc4167
CMAKE_SUBDIR src
)
diff --git a/docs/KNOWN-ISSUES.md b/docs/KNOWN-ISSUES.md
index 8a5b03b..5b87a20 100644
--- a/docs/KNOWN-ISSUES.md
+++ b/docs/KNOWN-ISSUES.md
@@ -3,6 +3,17 @@
This doc lists known issues in Tink. Please report new issues by opening new
tickets or emailing the maintainers at `tink-users@googlegroups.com`.
+## C++
+
+* Before 1.4.0, AES-CTR-HMAC-AEAD keys and the
+ [EncryptThenAuthenticate](https://github.com/google/tink/blob/master/cc/subtle/encrypt_then_authenticate.cc)
+ subtle implementation may be vulnerable to chosen-ciphertext attacks. An
+ attacker can generate ciphertexts that bypass the HMAC verification if and
+ only if all of the following conditions are true:
+ - Tink C++ is used on systems where `size_t` is a 32-bit integer. This is
+ usually the case on 32-bit machines.
+ - The attacker can specify long (>= 2^29 bytes ~ 536MB) associated data.
+
## Java
* Tink supports Java 7 or newer. Please file a ticket if you want to support
diff --git a/docs/PYTHON-HOWTO.md b/docs/PYTHON-HOWTO.md
index 7d1596a..c6b2372 100644
--- a/docs/PYTHON-HOWTO.md
+++ b/docs/PYTHON-HOWTO.md
@@ -156,20 +156,23 @@
encrypt or decrypt data:
```python
- import tink
- from tink import aead
+import tink
+from tink import aead
- # Register all AEAD primitives
- aead.register()
+plaintext = b'your data...'
+associated_data = b'context'
- # 1. Get a handle to the key material.
- keyset_handle = tink.new_keyset_handle(aead.aead_key_templates.AES256_GCM)
+# Register all AEAD primitives
+aead.register()
- # 2. Get the primitive.
- aead_primitive = keyset_handle.primitive(aead.Aead)
+# 1. Get a handle to the key material.
+keyset_handle = tink.new_keyset_handle(aead.aead_key_templates.AES256_GCM)
- # 3. Use the primitive.
- ciphertext = aead_primitive.encrypt(plaintext, associated data)
+# 2. Get the primitive.
+aead_primitive = keyset_handle.primitive(aead.Aead)
+
+# 3. Use the primitive.
+ciphertext = aead_primitive.encrypt(plaintext, associated_data)
```
### Deterministic symmetric key encryption
@@ -179,20 +182,23 @@
primitive to encrypt or decrypt data:
```python
- import tink
- from tink import daead
+import tink
+from tink import daead
- # Register all deterministic AEAD primitives
- daead.register()
+plaintext = b'your data...'
+associated_data = b'context'
- # 1. Get a handle to the key material.
- keyset_handle = tink.new_keyset_handle(daead.deterministic_aead_key_templates.AES256_SIV)
+# Register all deterministic AEAD primitives
+daead.register()
- # 2. Get the primitive.
- daead_primitive = keyset_handle.primitive(daead.DeterministicAead)
+# 1. Get a handle to the key material.
+keyset_handle = tink.new_keyset_handle(daead.deterministic_aead_key_templates.AES256_SIV)
- # 3. Use the primitive.
- ciphertext = daead_primitive.encrypt_deterministically(plaintext, associated data)
+# 2. Get the primitive.
+daead_primitive = keyset_handle.primitive(daead.DeterministicAead)
+
+# 3. Use the primitive.
+ciphertext = daead_primitive.encrypt_deterministically(plaintext, associated_data)
```
### Message Authentication Code
@@ -201,23 +207,25 @@
[MAC (Message Authentication Code)](PRIMITIVES.md#message-authentication-code):
```python
- import tink
- from tink import mac
+import tink
+from tink import mac
- # Register all MAC primitives
- mac.register()
+data = b'your data...'
- # 1. Get a handle to the key material.
- keyset_handle = tink.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
+# Register all MAC primitives
+mac.register()
- # 2. Get the primitive.
- mac = keyset_handle.primitive(mac.Mac)
+# 1. Get a handle to the key material.
+keyset_handle = tink.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
- # 3. Use the primitive to compute a tag,
- tag = mac.compute_mac(data)
+# 2. Get the primitive.
+mac = keyset_handle.primitive(mac.Mac)
- # ... or to verify a tag.
- mac.verify_mac(tag, data)
+# 3. Use the primitive to compute a tag,
+tag = mac.compute_mac(data)
+
+# ... or to verify a tag.
+mac.verify_mac(tag, data)
```
### Hybrid Encryption
@@ -227,34 +235,36 @@
one can use the following:
```python
- import tink
- from tink import hybrid
+import tink
+from tink import hybrid
- # Register all Hybrid primitives
- hybrid.register()
+plaintext = b'your data...'
+context = b'context'
- # 1. Generate the private key material.
- private_keyset_handle = tink.new_keyset_handle(hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)
+# Register all Hybrid primitives
+hybrid.register()
- # Obtain the public key material.
- public_keyset_handle = private_keyset_handle.public_keyset_handle()
+# 1. Generate the private key material.
+private_keyset_handle = tink.new_keyset_handle(hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)
- # Encryption
+# Obtain the public key material.
+public_keyset_handle = private_keyset_handle.public_keyset_handle()
- # 2. Get the primitive.
- hybrid_encrypt = public_keyset_handle.primitive(hybrid.HybridEncrypt)
+# Encryption
- # 3. Use the primitive.
- ciphertext = hybrid_encrypt.encrypt(plaintext, context)
+# 2. Get the primitive.
+hybrid_encrypt = public_keyset_handle.primitive(hybrid.HybridEncrypt)
- # Decryption
+# 3. Use the primitive.
+ciphertext = hybrid_encrypt.encrypt(plaintext, context)
- # 2. Get the primitive.
- hybrid_decrypt = private_keyset_handle.primitive(hybrid.HybridDecrypt)
+# Decryption
- # 3. Use the primitive.
- plaintext = hybrid_decrypt.decrypt(ciphertext, context)
+# 2. Get the primitive.
+hybrid_decrypt = private_keyset_handle.primitive(hybrid.HybridDecrypt)
+# 3. Use the primitive.
+plaintext = hybrid_decrypt.decrypt(ciphertext, context)
```
### Digital Signatures
@@ -263,31 +273,31 @@
[digital signature](PRIMITIVES.md#digital-signatures):
```python
- import tink
- from tink import signature
+import tink
+from tink import signature
- # Register key manager for signatures
- signature.register()
+# Register key manager for signatures
+signature.register()
- # Signing
- # 1. Generate the private key material.
- keyset_handle = tink.new_keyset_handle(signature.signature_key_templates.ED25519)
+# Signing
+# 1. Generate the private key material.
+keyset_handle = tink.new_keyset_handle(signature.signature_key_templates.ED25519)
- # 2. Get the primitive.
- signer = keyset_handle.primitive(signature.PublicKeySign)
+# 2. Get the primitive.
+signer = keyset_handle.primitive(signature.PublicKeySign)
- # 3. Use the primitive to sign.
- signature = signer.sign(b'your data')
+# 3. Use the primitive to sign.
+signature_data = signer.sign(b'your data')
- # Verifying
- # 1. Obtain the public key material.
- public_keyset_handle = keyset_handle.public_keyset_handle()
+# Verifying
+# 1. Obtain the public key material.
+public_keyset_handle = keyset_handle.public_keyset_handle()
- # 2. Get the primitive.
- verifier = public_keyset_handle.primitive(signature.PublicKeyVerify)
+# 2. Get the primitive.
+verifier = public_keyset_handle.primitive(signature.PublicKeyVerify)
- # 3. Use the primitive to verify.
- verifier.verify(signature, b'your data')
+# 3. Use the primitive to verify.
+verifier.verify(signature_data, b'your data')
```
### Envelope encryption
@@ -300,28 +310,32 @@
using the credentials in `credentials.json` as follows:
```python
- import tink
- from tink import aead
- from tink.integration import gcpkms
+import tink
+from tink import aead
+from tink.integration import gcpkms
- key_uri = 'gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar'
- gcp_credentials = 'credentials.json'
+key_uri = 'gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar'
+gcp_credentials = 'credentials.json'
- # Read the GCP credentials and setup client
- try:
- gcp_client = gcpkms.GcpKmsClient(key_uri, gcp_credentials)
- gcp_aead = gcp_client.get_aead(key_uri)
- except tink.TinkError as e:
- logging.error('Error initializing GCP client: %s', e)
- return 1
+plaintext = b'your data...'
+associated_data = b'context'
- # Create envelope AEAD primitive using AES256 GCM for encrypting the data
- try:
- key_template = aead.aead_key_templates.AES256_GCM
- env_aead = aead.KmsEnvelopeAead(key_template, gcp_aead)
- except tink.TinkError as e:
- logging.error('Error creating primitive: %s', e)
- return 1
- # Use env_aead to encrypt data
- ciphertext = env_aead.encrypt(plaintext, associated data)
+# Read the GCP credentials and setup client
+try:
+ gcp_client = gcpkms.GcpKmsClient(key_uri, gcp_credentials)
+ gcp_aead = gcp_client.get_aead(key_uri)
+except tink.TinkError as e:
+ logging.error('Error initializing GCP client: %s', e)
+ return 1
+
+# Create envelope AEAD primitive using AES256 GCM for encrypting the data
+try:
+ key_template = aead.aead_key_templates.AES256_GCM
+ env_aead = aead.KmsEnvelopeAead(key_template, gcp_aead)
+except tink.TinkError as e:
+ logging.error('Error creating primitive: %s', e)
+ return 1
+
+# Use env_aead to encrypt data
+ciphertext = env_aead.encrypt(plaintext, associated_data)
```
diff --git a/examples/java_src/helloworld/BUILD.bazel b/examples/java_src/helloworld/BUILD.bazel
index 878fcc9..22fc48f 100644
--- a/examples/java_src/helloworld/BUILD.bazel
+++ b/examples/java_src/helloworld/BUILD.bazel
@@ -16,9 +16,13 @@
],
deps = [
"@maven//:args4j_args4j",
- "@tink_java//:cleartext_keyset_handle",
- "@tink_java//:java",
- "@tink_java//:subtle",
+ "@tink_java//src/main/java/com/google/crypto/tink:aead",
+ "@tink_java//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "@tink_java//src/main/java/com/google/crypto/tink:json_keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:json_keyset_writer",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aead_config",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aead_key_templates",
],
)
diff --git a/go/aead/aead.go b/go/aead/aead.go
index 3398eae..e93b616 100644
--- a/go/aead/aead.go
+++ b/go/aead/aead.go
@@ -15,38 +15,6 @@
// Package aead provides implementations of the AEAD primitive.
//
// AEAD encryption assures the confidentiality and authenticity of the data. This primitive is CPA secure.
-//
-// Example:
-//
-// package main
-//
-// import (
-// "fmt"
-//
-// "github.com/google/tink/go/aead"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// func main() {
-//
-// kh, err := keyset.NewHandle(aead.AES256GCMKeyTemplate())
-// if err != nil {
-// // handle the error
-// }
-//
-// a := aead.New(kh)
-//
-// ct , err := a.Encrypt([]byte("this data needs to be encrypted"), []byte("associated data"))
-// if err != nil {
-// // handle error
-// }
-//
-// pt, err := a.Decrypt(ct, []byte("associated data"))
-// if err != nil {
-// //handle error
-// }
-//
-// }
package aead
import (
diff --git a/go/aead/aead_factory.go b/go/aead/aead_factory.go
index b5efd11..2873753 100644
--- a/go/aead/aead_factory.go
+++ b/go/aead/aead_factory.go
@@ -95,7 +95,8 @@
ctNoPrefix := ct[prefixSize:]
entries, err := a.ps.EntriesForPrefix(string(prefix))
if err == nil {
- for i := 0; i < len(entries); i++ {
+ // Attempt to decrypt with newer keys first because they more likely are the correct one.
+ for i := len(entries) - 1; i >= 0; i-- {
p, ok := (entries[i].Primitive).(tink.AEAD)
if !ok {
return nil, fmt.Errorf("aead_factory: not an AEAD primitive")
@@ -111,7 +112,7 @@
// try raw keys
entries, err := a.ps.RawEntries()
if err == nil {
- for i := 0; i < len(entries); i++ {
+ for i := len(entries) - 1; i >= 0; i-- {
p, ok := (entries[i].Primitive).(tink.AEAD)
if !ok {
return nil, fmt.Errorf("aead_factory: not an AEAD primitive")
diff --git a/go/aead/aead_test.go b/go/aead/aead_test.go
index f9ca3ae..7220bcc 100644
--- a/go/aead/aead_test.go
+++ b/go/aead/aead_test.go
@@ -15,13 +15,40 @@
package aead_test
import (
+ "log"
"testing"
+ "github.com/google/tink/go/aead"
"github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/keyset"
"github.com/google/tink/go/testutil"
)
-func TestAeadInit(t *testing.T) {
+func Example() {
+ kh, err := keyset.NewHandle(aead.AES256GCMKeyTemplate())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ a, err := aead.New(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct, err := a.Encrypt([]byte("this data needs to be encrypted"), []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = a.Decrypt(ct, []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+}
+
+func TestAEADInit(t *testing.T) {
// Check for AES-GCM key manager.
_, err := registry.GetKeyManager(testutil.AESGCMTypeURL)
if err != nil {
diff --git a/go/aead/aes_ctr_hmac_aead_key_manager.go b/go/aead/aes_ctr_hmac_aead_key_manager.go
index 87ad066..26497fd 100644
--- a/go/aead/aes_ctr_hmac_aead_key_manager.go
+++ b/go/aead/aes_ctr_hmac_aead_key_manager.go
@@ -139,11 +139,15 @@
// validateKey validates the given AesCtrHmacAeadKey proto.
func (km *aesCTRHMACAEADKeyManager) validateKey(key *aeadpb.AesCtrHmacAeadKey) error {
- err := keyset.ValidateKeyVersion(key.Version, aesCTRHMACAEADKeyVersion)
- if err != nil {
+ if err := keyset.ValidateKeyVersion(key.Version, aesCTRHMACAEADKeyVersion); err != nil {
return fmt.Errorf("aes_ctr_hmac_aead_key_manager: %v", err)
}
-
+ if err := keyset.ValidateKeyVersion(key.AesCtrKey.Version, aesCTRHMACAEADKeyVersion); err != nil {
+ return fmt.Errorf("aes_ctr_hmac_aead_key_manager: %v", err)
+ }
+ if err := keyset.ValidateKeyVersion(key.HmacKey.Version, aesCTRHMACAEADKeyVersion); err != nil {
+ return fmt.Errorf("aes_ctr_hmac_aead_key_manager: %v", err)
+ }
// Validate AesCtrKey.
keySize := uint32(len(key.AesCtrKey.KeyValue))
if err := subtle.ValidateAESKeySize(keySize); err != nil {
diff --git a/go/daead/aes_siv_key_manager.go b/go/daead/aes_siv_key_manager.go
index 4b0227f..82c1f0f 100644
--- a/go/daead/aes_siv_key_manager.go
+++ b/go/daead/aes_siv_key_manager.go
@@ -60,17 +60,34 @@
return ret, nil
}
-// NewKey creates a new key, ignoring the specification in the given serialized key format
-// because the key size and other params are fixed.
+// NewKey creates a new key. serializedKeyFormat is not required, because there is only one
+// valid key format.
func (km *aesSIVKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
- return km.newAesSivKey(), nil
+ if serializedKeyFormat != nil {
+ keyFormat := new(aspb.AesSivKeyFormat)
+ if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
+ return nil, fmt.Errorf("aes_siv_key_manager: invalid key format")
+ }
+ if keyFormat.KeySize != subtle.AESSIVKeySize {
+ return nil, fmt.Errorf("aes_siv_key_manager: keyFormat.KeySize != %d", subtle.AESSIVKeySize)
+ }
+ }
+ keyValue := random.GetRandomBytes(subtle.AESSIVKeySize)
+ key := &aspb.AesSivKey{
+ Version: aesSIVKeyVersion,
+ KeyValue: keyValue,
+ }
+ return key, nil
}
-// NewKeyData creates a new KeyData, ignoring the specification in the given serialized key format
-// because the key size and other params are fixed.
+// NewKeyData creates a new KeyData. serializedKeyFormat is not required, because there is only one
+// valid key format.
// It should be used solely by the key management API.
func (km *aesSIVKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) {
- key := km.newAesSivKey()
+ key, err := km.NewKey(serializedKeyFormat)
+ if err != nil {
+ return nil, err
+ }
serializedKey, err := proto.Marshal(key)
if err != nil {
return nil, err
@@ -104,12 +121,3 @@
}
return nil
}
-
-// newAesSivKey creates a new AesSivKey.
-func (km *aesSIVKeyManager) newAesSivKey() *aspb.AesSivKey {
- keyValue := random.GetRandomBytes(subtle.AESSIVKeySize)
- return &aspb.AesSivKey{
- Version: aesSIVKeyVersion,
- KeyValue: keyValue,
- }
-}
diff --git a/go/daead/aes_siv_key_manager_test.go b/go/daead/aes_siv_key_manager_test.go
index ae4a165..3284b62 100644
--- a/go/daead/aes_siv_key_manager_test.go
+++ b/go/daead/aes_siv_key_manager_test.go
@@ -102,6 +102,24 @@
}
}
+func TestAESSIVNewKeyInvalid(t *testing.T) {
+ km, err := registry.GetKeyManager(testutil.AESSIVTypeURL)
+ if err != nil {
+ t.Errorf("cannot obtain AESSIV key manager: %s", err)
+ }
+ keyFormat := &aspb.AesSivKeyFormat{
+ KeySize: subtle.AESSIVKeySize - 1,
+ }
+ serializedKeyFormat, err := proto.Marshal(keyFormat)
+ if err != nil {
+ t.Errorf("proto.Marshal(keyFormat) = %v; want nil", err)
+ }
+ _, err = km.NewKey(serializedKeyFormat)
+ if err == nil {
+ t.Errorf("km.NewKey(serializedKeyFormat) = _, nil; want _, err")
+ }
+}
+
func TestAESSIVDoesSupport(t *testing.T) {
km, err := registry.GetKeyManager(testutil.AESSIVTypeURL)
if err != nil {
diff --git a/go/daead/daead.go b/go/daead/daead.go
index 3342188..69ca616 100644
--- a/go/daead/daead.go
+++ b/go/daead/daead.go
@@ -16,45 +16,6 @@
//
// Unlike AEAD, implementations of this interface are not semantically secure, because
// encrypting the same plaintex always yields the same ciphertext.
-//
-// Example:
-//
-// package main
-//
-// import (
-// "fmt"
-//
-// "github.com/google/tink/go/daead"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// func main() {
-//
-// kh, err := keyset.NewHandle(daead.AESSIVKeyTemplate())
-// if err != nil {
-// // handle the error
-// }
-//
-// d := daead.New(kh)
-//
-// ct1 , err := d.EncryptDeterministically([]byte("this data needs to be encrypted"), []byte("additional data"))
-// if err != nil {
-// // handle error
-// }
-//
-// pt , err := d.DecryptDeterministically(ct, []byte("additional data"))
-// if err != nil {
-// // handle error
-// }
-//
-// ct2 , err := d.EncryptDeterministically([]byte("this data needs to be encrypted"), []byte("additional data"))
-// if err != nil {
-// // handle error
-// }
-//
-// // ct1 will be equal to ct2
-//
-// }
package daead
import (
diff --git a/go/daead/daead_test.go b/go/daead/daead_test.go
index 4c6b852..40fabb6 100644
--- a/go/daead/daead_test.go
+++ b/go/daead/daead_test.go
@@ -15,12 +15,49 @@
package daead_test
import (
+ "bytes"
+ "log"
"testing"
"github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/daead"
+ "github.com/google/tink/go/keyset"
"github.com/google/tink/go/testutil"
)
+func Example() {
+ kh, err := keyset.NewHandle(daead.AESSIVKeyTemplate())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ d, err := daead.New(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct1, err := d.EncryptDeterministically([]byte("this data needs to be encrypted"), []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = d.DecryptDeterministically(ct1, []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct2, err := d.EncryptDeterministically([]byte("this data needs to be encrypted"), []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if !bytes.Equal(ct1, ct2) {
+ log.Fatal("ct1 != ct2")
+ }
+
+ // Output:
+}
+
func TestDeterministicAEADInit(t *testing.T) {
// Check for AES-SIV key manager.
_, err := registry.GetKeyManager(testutil.AESSIVTypeURL)
diff --git a/go/hybrid/BUILD.bazel b/go/hybrid/BUILD.bazel
index f4d78f2..5b2badf 100644
--- a/go/hybrid/BUILD.bazel
+++ b/go/hybrid/BUILD.bazel
@@ -37,11 +37,14 @@
"ecies_aead_hkdf_hybrid_encrypt_test.go",
"hybrid_factory_test.go",
"hybrid_key_templates_test.go",
+ "hybrid_test.go",
"register_ecies_aead_hkdf_dem_helper_test.go",
],
embed = [":go_default_library"],
deps = [
"//aead:go_default_library",
+ "//hybrid/subtle:go_default_library",
+ "//keyset:go_default_library",
"//mac:go_default_library",
"//proto:common_go_proto",
"//proto:ecies_aead_hkdf_go_proto",
diff --git a/go/hybrid/ecies_aead_hkdf_private_key_manager.go b/go/hybrid/ecies_aead_hkdf_private_key_manager.go
index e3ac833..1359126 100644
--- a/go/hybrid/ecies_aead_hkdf_private_key_manager.go
+++ b/go/hybrid/ecies_aead_hkdf_private_key_manager.go
@@ -17,12 +17,12 @@
import (
"errors"
"fmt"
- "strings"
"github.com/golang/protobuf/proto"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/hybrid/subtle"
"github.com/google/tink/go/keyset"
+ commonpb "github.com/google/tink/go/proto/common_go_proto"
eahpb "github.com/google/tink/go/proto/ecies_aead_hkdf_go_proto"
tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)
@@ -171,11 +171,11 @@
if err != nil {
return err
}
- if strings.Compare(params.KemParams.HkdfHashType.String(), "HashType_UNKNOWN_HASH") == 0 {
+ if params.KemParams.HkdfHashType == commonpb.HashType_UNKNOWN_HASH {
return errors.New("hash unsupported for HMAC")
}
- if strings.Compare(params.EcPointFormat.String(), "EcPointFormat_UNKNOWN_FORMAT") == 0 {
+ if params.EcPointFormat == commonpb.EcPointFormat_UNKNOWN_FORMAT {
return errors.New("unknown EC point format")
}
km, err := registry.GetKeyManager(params.DemParams.AeadDem.TypeUrl)
diff --git a/go/hybrid/hybrid.go b/go/hybrid/hybrid.go
index 2fb9570..305b6e5 100644
--- a/go/hybrid/hybrid.go
+++ b/go/hybrid/hybrid.go
@@ -27,38 +27,6 @@
// context, but should be bound to the resulting ciphertext, i.e. the
// ciphertext allows for checking the integrity of contextInfo (but there are
// no guarantees wrt. the secrecy or authenticity of contextInfo).
-//
-// Example:
-//
-// package main
-//
-// import (
-// "github.com/google/tink/go/hybrid"
-// "github.com/google/tink/go/core/registry"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// func main() {
-//
-// kh , err := keyset.NewHandle(hybrid.ECIESHKDFAES128CTRHMACSHA256KeyTemplate())
-// if err != nil {
-// //handle error
-// }
-// h := hybrid.NewHybridEncrypt(kh)
-//
-// ct, err = h.Encrypt([]byte("secret message"), []byte("context info"))
-// if err != nil {
-// // handle error
-// }
-//
-// khd , err := keyset.NewHandle( .....); /// get a handle on the decryption key material
-// hd := hybrid.NewHybridDecrypt(khd)
-//
-// pt, err := hd.Decrypt(ct, []byte("context info"))
-// if err != nil {
-// // handle error
-// }
-// }
package hybrid
import (
diff --git a/go/hybrid/hybrid_test.go b/go/hybrid/hybrid_test.go
new file mode 100644
index 0000000..dfe2235
--- /dev/null
+++ b/go/hybrid/hybrid_test.go
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package hybrid_test
+
+import (
+ "log"
+
+ "github.com/google/tink/go/hybrid"
+ "github.com/google/tink/go/keyset"
+)
+
+func Example() {
+ khPriv, err := keyset.NewHandle(hybrid.ECIESHKDFAES128CTRHMACSHA256KeyTemplate())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ khPub, err := khPriv.Public()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ enc, err := hybrid.NewHybridEncrypt(khPub)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct, err := enc.Encrypt([]byte("this data needs to be encrypted"), []byte("context info"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ dec, err := hybrid.NewHybridDecrypt(khPriv)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = dec.Decrypt(ct, []byte("context info"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+}
diff --git a/go/integration/gcpkms/BUILD.bazel b/go/integration/gcpkms/BUILD.bazel
index 92ceaa3..6ad4f6a 100644
--- a/go/integration/gcpkms/BUILD.bazel
+++ b/go/integration/gcpkms/BUILD.bazel
@@ -23,7 +23,10 @@
go_test(
name = "go_default_test",
- srcs = ["gcp_kms_aead_test.go"],
+ srcs = [
+ "gcp_kms_aead_test.go",
+ "gcp_kms_client_test.go",
+ ],
data = [
"@tink_base//testdata:credentials",
"@tink_base//testdata:ecies_keysets",
diff --git a/go/integration/gcpkms/gcp_kms_client.go b/go/integration/gcpkms/gcp_kms_client.go
index 4c0c1cc..b2539d4 100644
--- a/go/integration/gcpkms/gcp_kms_client.go
+++ b/go/integration/gcpkms/gcp_kms_client.go
@@ -16,48 +16,6 @@
// Package gcpkms provides integration with the GCP Cloud KMS.
// Tink APIs work with GCP and AWS KMS.
-// GCP Example below:
-//
-// package main
-//
-// import (
-// "github.com/google/tink/go/aead"
-// "github.com/google/tink/go/core/registry"
-// "github.com/google/tink/go/integration/gcpkms"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// const (
-// keyURI = "gcp-kms://......"
-// )
-//
-// func main() {
-// gcpclient, err := gcpkms.NewClientWithCredentials(keyURI, "/mysecurestorage/credentials.json")
-// if err != nil {
-// //handle error
-// }
-// registry.RegisterKMSClient(gcpclient)
-//
-// dek := aead.AES128CTRHMACSHA256KeyTemplate()
-// kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
-// if err != nil {
-// // handle error
-// }
-// a, err := aead.New(kh)
-// if err != nil {
-// // handle error
-// }
-//
-// ct, err = a.Encrypt([]byte("secret message"), []byte("associated data"))
-// if err != nil {
-// // handle error
-// }
-//
-// pt, err = a.Decrypt(ct, []byte("associated data"))
-// if err != nil {
-// // handle error
-// }
-// }
package gcpkms
import (
diff --git a/go/integration/gcpkms/gcp_kms_client_test.go b/go/integration/gcpkms/gcp_kms_client_test.go
new file mode 100644
index 0000000..d8bb8c4
--- /dev/null
+++ b/go/integration/gcpkms/gcp_kms_client_test.go
@@ -0,0 +1,55 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package gcpkms
+
+import (
+ "log"
+
+ "github.com/google/tink/go/aead"
+ "github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/keyset"
+)
+
+func Example() {
+ const keyURI = "gcp-kms://......"
+
+ gcpclient, err := NewClientWithCredentials(keyURI, "/mysecurestorage/credentials.json")
+ if err != nil {
+ log.Fatal(err)
+ }
+ registry.RegisterKMSClient(gcpclient)
+
+ dek := aead.AES128CTRHMACSHA256KeyTemplate()
+ kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
+ if err != nil {
+ log.Fatal(err)
+ }
+ a, err := aead.New(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct, err := a.Encrypt([]byte("this data needs to be encrypted"), []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = a.Decrypt(ct, []byte("this data needs to be authenticated, but not encrypted"))
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/go/integration/hcvault/BUILD.bazel b/go/integration/hcvault/BUILD.bazel
index 3cfca49..624b48e 100644
--- a/go/integration/hcvault/BUILD.bazel
+++ b/go/integration/hcvault/BUILD.bazel
@@ -20,7 +20,15 @@
go_test(
name = "go_default_test",
- srcs = ["hcvault_aead_test.go"],
+ srcs = [
+ "hcvault_aead_test.go",
+ "hcvault_client_test.go",
+ ],
data = ["//integration/hcvault/testdata:server_tls_files"],
embed = [":go_default_library"],
+ deps = [
+ "//aead:go_default_library",
+ "//core/registry:go_default_library",
+ "//keyset:go_default_library",
+ ]
)
diff --git a/go/integration/hcvault/hcvault_client.go b/go/integration/hcvault/hcvault_client.go
index 55d8b81..5e5d31d 100644
--- a/go/integration/hcvault/hcvault_client.go
+++ b/go/integration/hcvault/hcvault_client.go
@@ -15,55 +15,6 @@
////////////////////////////////////////////////////////////////////////////////
// Package hcvault provides integration with the HashiCorp Vault (https://www.vaultproject.io/).
-// Below there is an example of how the integration code can be used:
-
-// package main
-//
-// import (
-// "fmt"
-// "log"
-//
-// "github.com/google/tink/go/aead"
-// "github.com/google/tink/go/core/registry"
-// "github.com/google/tink/go/integration/hcvault"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// const (
-// keyURI = "hcvault://hcvault.corp.com:8200/transit/keys/key-1"
-// )
-//
-// func main() {
-// tlsConf := getTLSConfig()
-// token := getVaultToken()
-// vaultClient, err := hcvault.NewClient(keyURI, tlsConf, token)
-// if err != nil {
-// // handle error
-// }
-// registry.RegisterKMSClient(vaultClient)
-//
-// dek := aead.AES128CTRHMACSHA256KeyTemplate()
-// kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
-// if err != nil {
-// // handle error
-// }
-// a, err := aead.New(kh)
-// if err != nil {
-// // handle error
-// }
-//
-// msg := "secret message"
-// ct, err := a.Encrypt([]byte(msg), nil)
-// if err != nil {
-// // handle error
-// }
-//
-// pt, err := a.Decrypt(ct, nil)
-// if err != nil {
-// // handle error
-// }
-// }
-
package hcvault
import (
diff --git a/go/integration/hcvault/hcvault_client_test.go b/go/integration/hcvault/hcvault_client_test.go
new file mode 100644
index 0000000..d5c9a25
--- /dev/null
+++ b/go/integration/hcvault/hcvault_client_test.go
@@ -0,0 +1,65 @@
+// Copyright 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package hcvault
+
+import (
+ "crypto/tls"
+ "log"
+
+ "github.com/google/tink/go/aead"
+ "github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/keyset"
+)
+
+func Example() {
+ const keyURI = "hcvault://hcvault.corp.com:8200/transit/keys/key-1"
+
+ vaultClient, err := NewClient(keyURI, tlsConfig(), vaultToken())
+ if err != nil {
+ log.Fatal(err)
+ }
+ registry.RegisterKMSClient(vaultClient)
+
+ dek := aead.AES128CTRHMACSHA256KeyTemplate()
+ kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
+ if err != nil {
+ log.Fatal(err)
+ }
+ a, err := aead.New(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ct, err := a.Encrypt([]byte("this data needs to be encrypted"), nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = a.Decrypt(ct, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func tlsConfig() *tls.Config {
+ // Return a TLS configuration used to communicate with Vault server via HTTPS.
+ return nil
+}
+
+func vaultToken() string {
+ return "" // Your Vault token.
+}
diff --git a/go/mac/mac.go b/go/mac/mac.go
index 873e549..e6045ef 100644
--- a/go/mac/mac.go
+++ b/go/mac/mac.go
@@ -17,37 +17,6 @@
// MAC computes a tag for a given message that can be used to authenticate a
// message. MAC protects data integrity as well as provides for authenticity
// of the message.
-//
-// Example:
-//
-// package main
-//
-// import (
-// "fmt"
-//
-// "github.com/google/tink/go/mac"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// func main() {
-//
-// kh, err := keyset.NewHandle(mac.HMACSHA256Tag256KeyTemplate())
-// if err != nil {
-// // handle the error
-// }
-//
-// m := mac.New(kh)
-//
-// mac , err := m.ComputeMac([]byte("this data needs to be MACed"))
-// if err != nil {
-// // handle error
-// }
-//
-// if m.VerifyMAC(mac, []byte("this data needs to be MACed")); err != nil {
-// //handle error
-// }
-//
-// }
package mac
import (
diff --git a/go/mac/mac_test.go b/go/mac/mac_test.go
index b9c139e..bf2280e 100644
--- a/go/mac/mac_test.go
+++ b/go/mac/mac_test.go
@@ -15,9 +15,12 @@
package mac_test
import (
+ "log"
"testing"
"github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/mac"
"github.com/google/tink/go/testutil"
)
@@ -31,3 +34,26 @@
t.Errorf("unexpected error: %s", err)
}
}
+
+func Example() {
+ kh, err := keyset.NewHandle(mac.HMACSHA256Tag256KeyTemplate())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ m, err := mac.New(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ mac, err := m.ComputeMAC([]byte("this data needs to be MACed"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if m.VerifyMAC(mac, []byte("this data needs to be MACed")); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+}
diff --git a/go/mac/subtle/hmac.go b/go/mac/subtle/hmac.go
index 99fb5b6..d969ca9 100644
--- a/go/mac/subtle/hmac.go
+++ b/go/mac/subtle/hmac.go
@@ -32,13 +32,6 @@
minTagSizeInBytes = uint32(10)
)
-// Maximum tag size in bytes for each hash type
-var maxTagSizeInBytes = map[string]uint32{
- "SHA1": uint32(20),
- "SHA256": uint32(32),
- "SHA512": uint32(64),
-}
-
var errHMACInvalidInput = errors.New("HMAC: invalid input")
// HMAC implementation of interface tink.MAC
@@ -68,11 +61,11 @@
// ValidateHMACParams validates parameters of HMAC constructor.
func ValidateHMACParams(hash string, keySize uint32, tagSize uint32) error {
// validate tag size
- maxTagSize, found := maxTagSizeInBytes[hash]
- if !found {
- return fmt.Errorf("invalid hash algorithm")
+ digestSize, err := subtle.GetHashDigestSize(hash)
+ if err != nil {
+ return err
}
- if tagSize > maxTagSize {
+ if tagSize > digestSize {
return fmt.Errorf("tag size too big")
}
if tagSize < minTagSizeInBytes {
diff --git a/go/signature/signature.go b/go/signature/signature.go
index bfd7458..cfc2c2a 100644
--- a/go/signature/signature.go
+++ b/go/signature/signature.go
@@ -16,49 +16,6 @@
// primitives.
//
// To sign data using Tink you can use ECDSA or ED25519 key templates.
-//
-// Example:
-//
-// package main
-//
-// import (
-// "fmt"
-//
-// "github.com/google/tink/go/signature"
-// "github.com/google/tink/go/keyset"
-// )
-//
-// func main() {
-//
-// kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) // other key templates can also be used
-// if err != nil {
-// // handle the error
-// }
-//
-// s, err := signature.NewSigner(kh)
-// if err != nil {
-// // handle error
-// }
-//
-// a , err := s.Sign([]byte("this data needs to be signed"))
-// if err != nil {
-// // handle the error
-// }
-//
-// pubkh, err := kh.Public()
-// if err != nil {
-// // handle the error
-// }
-//
-// v, err := signature.NewVerifier(pubkh)
-// if err != nil {
-// // handle the error
-// }
-//
-// if err := v.Verify(a, []byte("this data needs to be signed")); err != nil {
-// // handle the error
-// }
-// }
package signature
import (
diff --git a/go/signature/signature_test.go b/go/signature/signature_test.go
index cc8cdbc..55ef2a2 100644
--- a/go/signature/signature_test.go
+++ b/go/signature/signature_test.go
@@ -15,9 +15,12 @@
package signature_test
import (
+ "log"
"testing"
"github.com/google/tink/go/core/registry"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/signature"
"github.com/google/tink/go/testutil"
)
@@ -34,3 +37,36 @@
t.Errorf("unexpected error: %s", err)
}
}
+
+func Example() {
+ kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) // Other key templates can also be used.
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ s, err := signature.NewSigner(kh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ a, err := s.Sign([]byte("this data needs to be signed"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ pubkh, err := kh.Public()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ v, err := signature.NewVerifier(pubkh)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := v.Verify(a, []byte("this data needs to be signed")); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+}
diff --git a/go/streamingaead/aes_gcm_hkdf_key_manager.go b/go/streamingaead/aes_gcm_hkdf_key_manager.go
index 61b917b..8359275 100644
--- a/go/streamingaead/aes_gcm_hkdf_key_manager.go
+++ b/go/streamingaead/aes_gcm_hkdf_key_manager.go
@@ -150,7 +150,7 @@
if params.HkdfHashType == commonpb.HashType_UNKNOWN_HASH {
return errors.New("unknown HKDF hash type")
}
- if params.CiphertextSegmentSize < params.DerivedKeySize+subtle.NoncePrefixInBytes+subtle.TagSizeInBytes+2 {
+ if params.CiphertextSegmentSize < params.DerivedKeySize+subtle.AESGCMHKDFNoncePrefixInBytes+subtle.AESGCMHKDFTagSizeInBytes+2 {
return fmt.Errorf("ciphertext segment_size must be at least (derived_key_size + noncePrefixInBytes + " +
"tagSizeInBytes + 2")
}
diff --git a/go/streamingaead/streamingaead.go b/go/streamingaead/streamingaead.go
index 4932f90..232cf83 100644
--- a/go/streamingaead/streamingaead.go
+++ b/go/streamingaead/streamingaead.go
@@ -14,107 +14,8 @@
// Package streamingaead provides implementations of the streaming AEAD primitive.
//
-// AEAD encryption assures the confidentiality and authenticity of the data. This primitive is CPA secure.
-//
-// Example:
-//
-// import (
-// "io"
-// "io/ioutil"
-// "log"
-// "os"
-// "path/filepath"
-//
-// "github.com/google/tink/go/aead"
-// "github.com/google/tink/go/keyset"
-// "github.com/google/tink/go/streamingaead"
-// )
-//
-// func main() {
-// dir, err := ioutil.TempDir("", "streamingaead")
-// if err != nil {
-// log.Fatal(err)
-// }
-// defer os.RemoveAll(dir)
-//
-// var (
-// srcFilename = filepath.Join(dir, "plaintext.src")
-// ctFilename = filepath.Join(dir, "ciphertext.bin")
-// dstFilename = filepath.Join(dir, "plaintext.dst")
-// )
-//
-// if err := ioutil.WriteFile(srcFilename, []byte("this data needs to be encrypted"), 0666); err != nil {
-// log.Fatal(err)
-// }
-//
-// kh, err := keyset.NewHandle(streamingaead.AES256GCMHKDF4KBKeyTemplate())
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// a, err := streamingaead.New(kh)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// srcFile, err := os.Open(srcFilename)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// ctFile, err := os.Create(ctFilename)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// w, err := a.NewEncryptingWriter(ctFile, []byte("associated data"))
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// if _, err := io.Copy(w, srcFile); err != nil {
-// log.Fatal(err)
-// }
-//
-// if err := w.Close(); err != nil {
-// log.Fatal(err)
-// }
-//
-// if err := ctFile.Close(); err != nil {
-// log.Fatal(err)
-// }
-// if err := srcFile.Close(); err != nil {
-// log.Fatal(err)
-// }
-//
-// // Decrypt encrypted file.
-//
-// ctFile, err = os.Open(ctFilename)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// dstFile, err := os.Create(dstFilename)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// r, err := a.NewDecryptingReader(ctFile, []byte("associated data"))
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// if _, err := io.Copy(dstFile, r); err != nil {
-// log.Fatal(err)
-// }
-//
-// if err := dstFile.Close(); err != nil {
-// log.Fatal(err)
-// }
-// if err := ctFile.Close(); err != nil {
-// log.Fatal(err)
-// }
-// }
+// AEAD encryption assures the confidentiality and authenticity of the data.
+// This primitive is CPA secure.
package streamingaead
import (
diff --git a/go/streamingaead/subtle/aes_gcm_hkdf.go b/go/streamingaead/subtle/aes_gcm_hkdf.go
index 14b9a01..26d30ca 100644
--- a/go/streamingaead/subtle/aes_gcm_hkdf.go
+++ b/go/streamingaead/subtle/aes_gcm_hkdf.go
@@ -12,7 +12,8 @@
//
////////////////////////////////////////////////////////////////////////////////
-// Package subtle provides subtle implementations of the Streaming AEAD primitive.
+// Package subtle provides subtle implementations of the streaming AEAD
+// primitive.
package subtle
import (
@@ -22,6 +23,7 @@
"errors"
"fmt"
"io"
+ "math"
subtleaead "github.com/google/tink/go/aead/subtle"
"github.com/google/tink/go/subtle/random"
@@ -29,33 +31,53 @@
)
const (
- // nonceSizeInBytes is the size of the IVs for GCM.
- nonceSizeInBytes = 12
+ // AESGCMHKDFNonceSizeInBytes is the size of the IVs for GCM.
+ AESGCMHKDFNonceSizeInBytes = 12
- // NoncePrefixInBytes is the nonce has the format nonce_prefix || ctr || last_block.
+ // AESGCMHKDFNoncePrefixInBytes is the nonce, which has the format:
+ //
+ // nonce_prefix || ctr || last_block.
+ //
// The nonce_prefix is constant for the whole file.
- // The ctr is a 32 bit ctr, the last_block is 1 if this is the
- // last block of the file and 0 otherwise.
- NoncePrefixInBytes = 7
+ //
+ // The ctr is a 32 bit ctr.
+ //
+ // last_block is 1 if this is the last block of the file and 0 otherwise.
+ AESGCMHKDFNoncePrefixInBytes = 7
- // TagSizeInBytes is the size of the tags of each ciphertext segment.
- TagSizeInBytes = 16
+ // AESGCMHKDFTagSizeInBytes is the size of the tags of each ciphertext
+ // segment.
+ AESGCMHKDFTagSizeInBytes = 16
)
-// AESGCMHKDF implements streaming encryption using AES-GCM with HKDF as key derivation function.
+// AESGCMHKDF implements streaming encryption using AES-GCM with HKDF as the
+// key derivation function.
//
-// Each ciphertext uses a new AES-GCM key that is derived from the key derivation key, a randomly
-// chosen salt of the same size as the key and a nonce prefix.
+// Each ciphertext uses a new AES-GCM key that is derived from the key
+// derivation key, a randomly chosen salt of the same size as the key and a
+// nonce prefix.
//
-// The format of a ciphertext is header || segment_0 || segment_1 || ... || segment_k. The
-// header has size HeaderLength(). Its format is headerLength || salt || prefix. where
-// headerLength is 1 byte determining the size of the header, salt is a salt used in the key
-// derivation and prefix is the prefix of the nonce. In principle headerLength is redundant
-// information, since the length of the header can be determined from the key size.
+// The format of a ciphertext is:
//
-// segment_i is the i-th segment of the ciphertext. The size of segment_1 .. segment_{k-1} is
-// ciphertextSegmentSize. segment_0 is shorter, so that segment_0, the header and other information
-// of size firstSegmentOffset align with ciphertextSegmentSize.
+// header || segment_0 || segment_1 || ... || segment_k.
+//
+// The format of header is:
+//
+// headerLength || salt || prefix
+//
+// headerLength is 1 byte determining the size of the header and can be
+// obtained via HeaderLength(). In principle headerLength is redundant
+// information, since the length of the header can be determined from the key
+// size.
+//
+// salt is a salt used in the key derivation.
+//
+// prefix is the prefix of the nonce.
+//
+// segment_i is the i-th segment of the ciphertext. The size of segment_1 ..
+// segment_{k-1} is ciphertextSegmentSize. segment_0 is shorter, so that
+// segment_0, the header and other information of size firstSegmentOffset align
+// with ciphertextSegmentSize.
type AESGCMHKDF struct {
MainKey []byte
hkdfAlg string
@@ -65,14 +87,22 @@
plaintextSegmentSize int
}
-// NewAESGCMHKDF initializes a streaming primitive with a key derivation key and encryption parameters.
+// NewAESGCMHKDF initializes a streaming primitive with a key derivation key
+// and encryption parameters.
//
-// mainKey argument is an input keying material used to derive sub keys.
-// hkdfAlg argument is a JCE MAC algorithm name, e.g., HmacSha256, used for the HKDF key derivation.
-// keySizeInBytes argument is a key size of the sub keys
+// mainKey is an input keying material used to derive sub keys.
+//
+// hkdfAlg is a JCE MAC algorithm name, e.g., HmacSha256, used for the HKDF key
+// derivation.
+//
+// keySizeInBytes argument is a key size of the sub keys.
+//
// ciphertextSegmentSize argument is the size of ciphertext segments.
-// firstSegmentOffset argument is the offset of the first ciphertext segment. That means the first
-// segment has size ciphertextSegmentSize - HeaderLength() - firstSegmentOffset
+//
+// firstSegmentOffset argument is the offset of the first ciphertext segment.
+// That means the first segment has size:
+//
+// ciphertextSegmentSize - HeaderLength() - firstSegmentOffset
func NewAESGCMHKDF(
mainKey []byte,
hkdfAlg string,
@@ -86,8 +116,8 @@
if err := subtleaead.ValidateAESKeySize(uint32(keySizeInBytes)); err != nil {
return nil, err
}
- headerLen := 1 + keySizeInBytes + NoncePrefixInBytes
- if ciphertextSegmentSize <= firstSegmentOffset+headerLen+TagSizeInBytes {
+ headerLen := 1 + keySizeInBytes + AESGCMHKDFNoncePrefixInBytes
+ if ciphertextSegmentSize <= firstSegmentOffset+headerLen+AESGCMHKDFTagSizeInBytes {
return nil, errors.New("ciphertextSegmentSize too small")
}
@@ -100,25 +130,40 @@
keySizeInBytes: keySizeInBytes,
ciphertextSegmentSize: ciphertextSegmentSize,
firstCiphertextSegmentOffset: firstSegmentOffset + headerLen,
- plaintextSegmentSize: ciphertextSegmentSize - TagSizeInBytes,
+ plaintextSegmentSize: ciphertextSegmentSize - AESGCMHKDFTagSizeInBytes,
}, nil
}
-// HeaderLength returns a length of the encryption header.
+// HeaderLength returns the length of the encryption header.
func (a *AESGCMHKDF) HeaderLength() int {
- return 1 + a.keySizeInBytes + NoncePrefixInBytes
+ return 1 + a.keySizeInBytes + AESGCMHKDFNoncePrefixInBytes
}
-// deriveKey returns a key derived from the given main key using salt and aad parameters.
+// deriveKey returns a key derived from the given main key using salt and aad
+// parameters.
func (a *AESGCMHKDF) deriveKey(salt, aad []byte) ([]byte, error) {
return subtle.ComputeHKDF(a.hkdfAlg, a.MainKey, salt, aad, uint32(a.keySizeInBytes))
}
-// aesGCMHKDFWriter works as a wrapper around underlying io.Writer, which is responsible for
-// encrypting written data. The data is encrypted and flushed in segments of a given size.
-// Once all the data is written aesGCMHKDFWriter must be closed.
+// newCipher creates a new AES-GCM cipher using the given key and the crypto library.
+func (a *AESGCMHKDF) newCipher(key []byte) (cipher.AEAD, error) {
+ aesCipher, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ aesGCMCipher, err := cipher.NewGCMWithTagSize(aesCipher, AESGCMHKDFTagSizeInBytes)
+ if err != nil {
+ return nil, err
+ }
+ return aesGCMCipher, nil
+}
+
+// aesGCMHKDFWriter works as a wrapper around underlying io.Writer, which is
+// responsible for encrypting written data. The data is encrypted and flushed
+// in segments of a given size. Once all the data is written aesGCMHKDFWriter
+// must be closed.
type aesGCMHKDFWriter struct {
- encryptedSegments int
+ encryptedSegments uint64
noncePrefix []byte
cipher cipher.AEAD
wr io.Writer
@@ -131,20 +176,21 @@
closed bool
}
-// NewEncryptingWriter returns a wrapper around underlying io.Writer, such that any write-operation
-// via the wrapper results in AEAD-encryption of the written data, using aad
-// as associated authenticated data. The associated data is not included in the ciphertext
-// and has to be passed in as parameter for decryption.
+// NewEncryptingWriter returns a wrapper around underlying io.Writer, such that
+// any write-operation via the wrapper results in AEAD-encryption of the
+// written data, using aad as associated authenticated data. The associated
+// data is not included in the ciphertext and has to be passed in as parameter
+// for decryption.
func (a *AESGCMHKDF) NewEncryptingWriter(w io.Writer, aad []byte) (io.WriteCloser, error) {
salt := random.GetRandomBytes(uint32(a.keySizeInBytes))
- noncePrefix := random.GetRandomBytes(NoncePrefixInBytes)
+ noncePrefix := random.GetRandomBytes(AESGCMHKDFNoncePrefixInBytes)
dkey, err := a.deriveKey(salt, aad)
if err != nil {
return nil, err
}
- cipher, err := newCipher(dkey)
+ cipher, err := a.newCipher(dkey)
if err != nil {
return nil, err
}
@@ -167,7 +213,8 @@
}, nil
}
-// Write encrypts passed data and passes the encrypted data to the underlying writer.
+// Write encrypts passed data and passes the encrypted data to the underlying
+// writer.
func (w *aesGCMHKDFWriter) Write(p []byte) (int, error) {
if w.closed {
return 0, errors.New("write on closed writer")
@@ -186,7 +233,10 @@
break
}
- nonce := generateSegmentNonce(w.noncePrefix, w.encryptedSegments, false)
+ nonce, err := generateAESGCMHKDFSegmentNonce(w.noncePrefix, w.encryptedSegments, false)
+ if err != nil {
+ return 0, err
+ }
w.ct = w.cipher.Seal(w.ct[0:0], nonce, w.pt[:ptLim], nil)
if _, err := w.wr.Write(w.ct); err != nil {
@@ -198,13 +248,17 @@
return pos, nil
}
-// Close encrypts the remaining data, flushes it to the underlying writer and closes this writer.
+// Close encrypts the remaining data, flushes it to the underlying writer and
+// closes this writer.
func (w *aesGCMHKDFWriter) Close() error {
if w.closed {
return nil
}
- nonce := generateSegmentNonce(w.noncePrefix, w.encryptedSegments, true)
+ nonce, err := generateAESGCMHKDFSegmentNonce(w.noncePrefix, w.encryptedSegments, true)
+ if err != nil {
+ return err
+ }
w.ct = w.cipher.Seal(w.ct[0:0], nonce, w.pt[0:w.ptPos], nil)
if _, err := w.wr.Write(w.ct); err != nil {
@@ -218,7 +272,7 @@
// aesGCMHKDFReader works as a wrapper around underlying io.Reader.
type aesGCMHKDFReader struct {
- decryptedSegments int
+ decryptedSegments uint64
noncePrefix []byte
cipher cipher.AEAD
underlyingReader io.Reader
@@ -230,9 +284,9 @@
firstSegmentOffset int
}
-// NewDecryptingReader returns a wrapper around underlying io.Reader, such that any read-operation
-// via the wrapper results in AEAD-decryption of the underlying ciphertext,
-// using aad as associated authenticated data.
+// NewDecryptingReader returns a wrapper around underlying io.Reader, such that
+// any read-operation via the wrapper results in AEAD-decryption of the
+// underlying ciphertext, using aad as associated authenticated data.
func (a *AESGCMHKDF) NewDecryptingReader(r io.Reader, aad []byte) (io.Reader, error) {
hlen := make([]byte, 1)
if _, err := io.ReadFull(r, hlen); err != nil {
@@ -247,7 +301,7 @@
return nil, fmt.Errorf("cannot read salt: %v", err)
}
- noncePrefix := make([]byte, NoncePrefixInBytes)
+ noncePrefix := make([]byte, AESGCMHKDFNoncePrefixInBytes)
if _, err := io.ReadFull(r, noncePrefix); err != nil {
return nil, fmt.Errorf("cannot read noncePrefix: %v", err)
}
@@ -257,7 +311,7 @@
return nil, err
}
- cipher, err := newCipher(dkey)
+ cipher, err := a.newCipher(dkey)
if err != nil {
return nil, err
}
@@ -300,7 +354,11 @@
} else {
segment = r.ctPos + n - 1
}
- nonce := generateSegmentNonce(r.noncePrefix, r.decryptedSegments, lastSegment)
+ nonce, err := generateAESGCMHKDFSegmentNonce(r.noncePrefix, r.decryptedSegments, lastSegment)
+ if err != nil {
+ return 0, nil
+ }
+
r.pt, err = r.cipher.Open(r.pt[0:0], nonce, r.ct[:segment], nil)
if err != nil {
return 0, err
@@ -320,31 +378,21 @@
return n, nil
}
-// newCipher creates a new AES-GCM cipher using the given key and the crypto library.
-func newCipher(key []byte) (cipher.AEAD, error) {
- aesCipher, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- ret, err := cipher.NewGCMWithTagSize(aesCipher, TagSizeInBytes)
- if err != nil {
- return nil, err
- }
- return ret, nil
-}
-
-func generateSegmentNonce(noncePrefix []byte, segmentNr int, last bool) []byte {
+func generateAESGCMHKDFSegmentNonce(noncePrefix []byte, segmentNr uint64, last bool) ([]byte, error) {
var l byte
if last {
l = 1
}
- nonce := make([]byte, nonceSizeInBytes)
+ nonce := make([]byte, AESGCMHKDFNonceSizeInBytes)
offs := 0
copy(nonce, noncePrefix)
offs += len(noncePrefix)
+ if segmentNr >= math.MaxUint32 {
+ return nil, errors.New("too many segments")
+ }
binary.BigEndian.PutUint32(nonce[offs:], uint32(segmentNr))
offs += 4
nonce[offs] = l
- return nonce
+ return nonce, nil
}
diff --git a/go/subtle/hkdf.go b/go/subtle/hkdf.go
index 41dbec8..cbc1660 100644
--- a/go/subtle/hkdf.go
+++ b/go/subtle/hkdf.go
@@ -27,23 +27,16 @@
minTagSizeInBytes = uint32(10)
)
-// Maximum tag size in bytes for each hash type
-var maxTagSizeInBytes = map[string]uint32{
- "SHA1": uint32(20),
- "SHA256": uint32(32),
- "SHA512": uint32(64),
-}
-
var errHKDFInvalidInput = errors.New("HKDF: invalid input")
// validateHKDFParams validates parameters of HKDF constructor.
func validateHKDFParams(hash string, keySize uint32, tagSize uint32) error {
// validate tag size
- maxTagSize, found := maxTagSizeInBytes[hash]
- if !found {
- return fmt.Errorf("invalid hash algorithm")
+ digestSize, err := GetHashDigestSize(hash)
+ if err != nil {
+ return err
}
- if tagSize > 255*maxTagSize {
+ if tagSize > 255*digestSize {
return fmt.Errorf("tag size too big")
}
if tagSize < minTagSizeInBytes {
diff --git a/go/subtle/subtle.go b/go/subtle/subtle.go
index 44fa4d0..af6b933 100644
--- a/go/subtle/subtle.go
+++ b/go/subtle/subtle.go
@@ -28,6 +28,23 @@
var errNilHashFunc = errors.New("nil hash function")
+// hashDigestSize maps hash algorithms to their digest size in bytes.
+var hashDigestSize = map[string]uint32{
+ "SHA1": uint32(20),
+ "SHA256": uint32(32),
+ "SHA384": uint32(48),
+ "SHA512": uint32(64),
+}
+
+// GetHashDigestSize returns the digest size of the specified hash algorithm.
+func GetHashDigestSize(hash string) (uint32, error) {
+ digestSize, ok := hashDigestSize[hash]
+ if !ok {
+ return 0, errors.New("invalid hash algorithm")
+ }
+ return digestSize, nil
+}
+
// ConvertHashName converts different forms of a hash name to the
// hash name that tink recognizes.
func ConvertHashName(name string) string {
diff --git a/java_src/BUILD.bazel b/java_src/BUILD.bazel
index 9dd02a3..ecec089 100644
--- a/java_src/BUILD.bazel
+++ b/java_src/BUILD.bazel
@@ -1,8 +1,7 @@
load("@build_bazel_rules_android//android:rules.bzl", "android_library")
load("//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
-load("//tools:jar_jar.bzl", "jar_jar")
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
licenses(["notice"])
@@ -201,21 +200,21 @@
gen_maven_jar_rules(
name = "tink-android",
doctitle = "Tink Cryptography API for Android",
+ resources = glob([
+ "src/main/resources/**",
+ ]),
root_packages = [
"com.google.crypto.tink",
- # The following package(s) will be shaded by the "tink-android-shaded" target.
+ ],
+ shaded_packages = [
+ # The following package(s) will be shaded, according to the rules
+ # specified in shading_rules.
"com.google.protobuf",
],
+ shading_rules = "jar_jar_rules.txt",
deps = lite_proto_deps + android_deps + cleartext_android_deps + subtle_deps,
)
-# Shade embedded packages to avoid dependency version conflicts in user projects.
-jar_jar(
- name = "tink-android-shaded",
- input_jar = ":tink-android",
- rules = "jar_jar_rules.txt",
-)
-
# TEST
java_library(
diff --git a/java_src/jar_jar_rules.txt b/java_src/jar_jar_rules.txt
index d3c6913..d6a3f01 100644
--- a/java_src/jar_jar_rules.txt
+++ b/java_src/jar_jar_rules.txt
@@ -1,2 +1,6 @@
# Rules File Format: https://github.com/bazelbuild/bazel/blob/master/third_party/jarjar/java/com/tonicsystems/jarjar/help.txt.
+#
+# Shade protobuf to avoid dependency version conflicts in user projects.
+# WARNING: the shaded package name com.google.crypto.tink.shaded.protobuf must
+# be kept in sync with src/main/resources/META-INF/proguard/tink.pro.
rule com.google.protobuf.** com.google.crypto.tink.shaded.protobuf.@1
diff --git a/java_src/proto/BUILD.bazel b/java_src/proto/BUILD.bazel
index 0d45b68..1099998 100644
--- a/java_src/proto/BUILD.bazel
+++ b/java_src/proto/BUILD.bazel
@@ -1,4 +1,4 @@
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
licenses(["notice"])
@@ -106,6 +106,16 @@
)
java_proto_library(
+ name = "jws_hmac_java_proto",
+ deps = ["@tink_base//proto:jws_hmac_proto"],
+)
+
+java_lite_proto_library(
+ name = "jws_hmac_java_proto_lite",
+ deps = ["@tink_base//proto:jws_hmac_proto"],
+)
+
+java_proto_library(
name = "aes_ctr_java_proto",
deps = ["@tink_base//proto:aes_ctr_proto"],
)
diff --git a/java_src/src/main/java/com/google/crypto/tink/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/BUILD.bazel
index 8d56e42..d26eb3b 100644
--- a/java_src/src/main/java/com/google/crypto/tink/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/BUILD.bazel
@@ -1,10 +1,562 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
load("@tink_base//:tink_version.bzl", "TINK_VERSION_LABEL")
load("@tink_base//tools:common.bzl", "template_rule")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+# Primitives
+
+java_library(
+ name = "aead",
+ srcs = ["Aead.java"],
+)
+
+java_library(
+ name = "streaming_aead",
+ srcs = ["StreamingAead.java"],
+)
+
+java_library(
+ name = "deterministic_aead",
+ srcs = ["DeterministicAead.java"],
+)
+
+java_library(
+ name = "hybrid_decrypt",
+ srcs = ["HybridDecrypt.java"],
+)
+
+java_library(
+ name = "hybrid_encrypt",
+ srcs = ["HybridEncrypt.java"],
+)
+
+java_library(
+ name = "mac",
+ srcs = ["Mac.java"],
+)
+
+java_library(
+ name = "key_wrap",
+ srcs = ["KeyWrap.java"],
+)
+
+java_library(
+ name = "public_key_sign",
+ srcs = ["PublicKeySign.java"],
+)
+
+java_library(
+ name = "public_key_verify",
+ srcs = ["PublicKeyVerify.java"],
+)
+
+# Other public interfaces
+
+java_library(
+ name = "crypto_format",
+ srcs = ["CryptoFormat.java"],
+ deps = ["//proto:tink_java_proto"],
+)
+
+android_library(
+ name = "crypto_format-android",
+ srcs = ["CryptoFormat.java"],
+ deps = ["//proto:tink_java_proto_lite"],
+)
+
+java_library(
+ name = "primitive_wrapper",
+ srcs = ["PrimitiveWrapper.java"],
+ deps = [":primitive_set"],
+)
+
+android_library(
+ name = "primitive_wrapper-android",
+ srcs = ["PrimitiveWrapper.java"],
+ deps = [":primitive_set-android"],
+)
+
+java_library(
+ name = "kms_client",
+ srcs = ["KmsClient.java"],
+ deps = [":aead"],
+)
+
+java_library(
+ name = "kms_clients",
+ srcs = ["KmsClients.java"],
+ deps = [":kms_client"],
+)
+
+java_library(
+ name = "keyset_writer",
+ srcs = ["KeysetWriter.java"],
+ deps = ["//proto:tink_java_proto"],
+)
+
+android_library(
+ name = "keyset_writer-android",
+ srcs = ["KeysetWriter.java"],
+ deps = ["//proto:tink_java_proto_lite"],
+)
+
+java_library(
+ name = "binary_keyset_writer",
+ srcs = ["BinaryKeysetWriter.java"],
+ deps = [
+ ":keyset_writer",
+ "//proto:tink_java_proto",
+ ],
+)
+
+android_library(
+ name = "binary_keyset_writer-android",
+ srcs = ["BinaryKeysetWriter.java"],
+ deps = [
+ ":keyset_writer-android",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "json_keyset_writer",
+ srcs = ["JsonKeysetWriter.java"],
+ deps = [
+ ":keyset_writer",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@maven//:org_json_json",
+ ],
+)
+
+android_library(
+ name = "json_keyset_writer-android",
+ srcs = ["JsonKeysetWriter.java"],
+ deps = [
+ ":keyset_writer",
+ ":keyset_writer-android",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@maven//:org_json_json",
+ ],
+)
+
+java_library(
+ name = "keyset_reader",
+ srcs = ["KeysetReader.java"],
+ deps = ["//proto:tink_java_proto"],
+)
+
+android_library(
+ name = "keyset_reader-android",
+ srcs = ["KeysetReader.java"],
+ deps = ["//proto:tink_java_proto_lite"],
+)
+
+java_library(
+ name = "binary_keyset_reader",
+ srcs = ["BinaryKeysetReader.java"],
+ deps = [
+ ":keyset_reader",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "binary_keyset_reader-android",
+ srcs = ["BinaryKeysetReader.java"],
+ deps = [
+ ":keyset_reader-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "json_keyset_reader",
+ srcs = ["JsonKeysetReader.java"],
+ deps = [
+ ":keyset_reader",
+ ":util",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:org_json_json",
+ ],
+)
+
+android_library(
+ name = "json_keyset_reader-android",
+ srcs = ["JsonKeysetReader.java"],
+ deps = [
+ ":keyset_reader-android",
+ ":util-android",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:org_json_json",
+ ],
+)
+
+java_library(
+ name = "private_key_manager",
+ srcs = ["PrivateKeyManager.java"],
+ deps = [
+ ":key_manager",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "private_key_manager-android",
+ srcs = ["PrivateKeyManager.java"],
+ deps = [
+ ":key_manager-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "privileged_registry",
+ srcs = ["PrivilegedRegistry.java"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":registry_cluster",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "privileged_registry-android",
+ srcs = ["PrivilegedRegistry.java"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":registry_cluster-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "key_type_manager",
+ srcs = ["KeyTypeManager.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "key_type_manager-android",
+ srcs = ["KeyTypeManager.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "key_template",
+ srcs = ["KeyTemplate.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+android_library(
+ name = "key_template-android",
+ srcs = ["KeyTemplate.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+java_library(
+ name = "config",
+ srcs = ["Config.java"],
+ deps = [
+ ":catalogue",
+ ":key_manager",
+ ":registry_cluster",
+ "//proto:config_java_proto",
+ ],
+)
+
+android_library(
+ name = "config-android",
+ srcs = ["Config.java"],
+ deps = [
+ ":catalogue-android",
+ ":key_manager-android",
+ ":registry_cluster-android",
+ "//proto:config_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "private_key_manager_impl",
+ srcs = ["PrivateKeyManagerImpl.java"],
+ deps = [
+ ":key_manager_impl",
+ ":key_type_manager",
+ ":private_key_manager",
+ ":private_key_type_manager",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "private_key_manager_impl-android",
+ srcs = ["PrivateKeyManagerImpl.java"],
+ deps = [
+ ":key_manager_impl-android",
+ ":key_type_manager-android",
+ ":private_key_manager-android",
+ ":private_key_type_manager-android",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "no_secret_keyset_handle",
+ srcs = ["NoSecretKeysetHandle.java"],
+ deps = [
+ ":keyset_reader",
+ ":registry_cluster",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "no_secret_keyset_handle-android",
+ srcs = ["NoSecretKeysetHandle.java"],
+ deps = [
+ ":keyset_reader-android",
+ ":registry_cluster-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "cleartext_keyset_handle",
+ srcs = ["CleartextKeysetHandle.java"],
+ deps = [
+ ":keyset_reader",
+ ":keyset_writer",
+ ":registry_cluster",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "cleartext_keyset_handle-android",
+ srcs = ["CleartextKeysetHandle.java"],
+ deps = [
+ ":keyset_reader-android",
+ ":keyset_writer-android",
+ ":registry_cluster-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "private_key_type_manager",
+ srcs = ["PrivateKeyTypeManager.java"],
+ deps = [
+ ":key_type_manager",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "private_key_type_manager-android",
+ srcs = ["PrivateKeyTypeManager.java"],
+ deps = [
+ ":key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "util",
+ srcs = ["Util.java"],
+ deps = ["//proto:tink_java_proto"],
+)
+
+android_library(
+ name = "util-android",
+ srcs = ["Util.java"],
+ deps = ["//proto:tink_java_proto_lite"],
+)
+
+java_library(
+ name = "catalogue",
+ srcs = ["Catalogue.java"],
+ deps = [
+ ":key_manager",
+ ":primitive_wrapper",
+ ],
+)
+
+android_library(
+ name = "catalogue-android",
+ srcs = ["Catalogue.java"],
+ deps = [
+ ":key_manager-android",
+ ":primitive_wrapper-android",
+ ],
+)
+
+java_library(
+ name = "key_manager",
+ srcs = ["KeyManager.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "key_manager-android",
+ srcs = ["KeyManager.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "key_manager_impl",
+ srcs = ["KeyManagerImpl.java"],
+ deps = [
+ ":key_manager",
+ ":key_type_manager",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "key_manager_impl-android",
+ srcs = ["KeyManagerImpl.java"],
+ deps = [
+ ":key_manager-android",
+ ":key_type_manager-android",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "primitive_set",
+ srcs = ["PrimitiveSet.java"],
+ deps = [
+ ":crypto_format",
+ "//proto:tink_java_proto",
+ ],
+)
+
+android_library(
+ name = "primitive_set-android",
+ srcs = ["PrimitiveSet.java"],
+ deps = [
+ ":crypto_format-android",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "registry_cluster",
+ srcs = [
+ "KeysetHandle.java",
+ "KeysetManager.java",
+ "Registry.java",
+ ],
+ deps = [
+ ":aead",
+ ":catalogue",
+ ":key_manager",
+ ":key_manager_impl",
+ ":key_template",
+ ":key_type_manager",
+ ":keyset_reader",
+ ":keyset_writer",
+ ":primitive_set",
+ ":primitive_wrapper",
+ ":private_key_manager",
+ ":private_key_manager_impl",
+ ":private_key_type_manager",
+ ":util",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+android_library(
+ name = "registry_cluster-android",
+ srcs = [
+ "KeysetHandle.java",
+ "KeysetManager.java",
+ "Registry.java",
+ ],
+ deps = [
+ ":aead",
+ ":catalogue-android",
+ ":key_manager-android",
+ ":key_manager_impl-android",
+ ":key_template-android",
+ ":key_type_manager-android",
+ ":keyset_reader-android",
+ ":keyset_writer-android",
+ ":primitive_set-android",
+ ":primitive_wrapper-android",
+ ":private_key_manager-android",
+ ":private_key_manager_impl-android",
+ ":private_key_type_manager-android",
+ ":util-android",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+template_rule(
+ name = "version_java",
+ src = "Version.java.templ",
+ out = "Version.java",
+ substitutions = {
+ "TINK_VERSION_LABEL": "%s" % TINK_VERSION_LABEL,
+ },
+)
+
+# Deprecated rules, will be removed soon.
full_protos = [
"//proto:common_java_proto",
@@ -58,15 +610,6 @@
# core, without restricted APIs
-template_rule(
- name = "version_java",
- src = "Version.java.templ",
- out = "Version.java",
- substitutions = {
- "TINK_VERSION_LABEL": "%s" % TINK_VERSION_LABEL,
- },
-)
-
java_library(
name = "core",
srcs = glob(
@@ -77,7 +620,7 @@
deps = full_protos + [
":primitives",
"//src/main/java/com/google/crypto/tink/annotations",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
"@com_google_protobuf//:protobuf_java",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -110,7 +653,7 @@
deps = lite_protos + [
":primitives",
"//src/main/java/com/google/crypto/tink/annotations",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/subtle:base64",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -129,18 +672,6 @@
)
java_library(
- name = "cleartext_keyset_handle",
- srcs = [
- ":cleartext_keyset_handle_srcs",
- ],
- javacopts = JAVACOPTS_OSS,
- deps = full_protos + [
- ":tink",
- "@com_google_protobuf//:protobuf_javalite",
- ],
-)
-
-java_library(
name = "cleartext_keyset_handle_android",
srcs = [
":cleartext_keyset_handle_srcs",
@@ -151,27 +682,3 @@
"@com_google_protobuf//:protobuf_javalite",
],
)
-
-java_library(
- name = "privileged_registry",
- srcs = ["PrivilegedRegistry.java"],
- javacopts = JAVACOPTS_OSS,
- visibility = ["//visibility:public"],
- deps = [
- ":core",
- "//proto:tink_java_proto",
- "@com_google_protobuf//:protobuf_javalite",
- ],
-)
-
-java_library(
- name = "privileged_registry-android",
- srcs = ["PrivilegedRegistry.java"],
- javacopts = JAVACOPTS_OSS,
- visibility = ["//visibility:public"],
- deps = [
- ":core-android",
- "//proto:tink_java_proto_lite",
- "@com_google_protobuf//:protobuf_javalite",
- ],
-)
diff --git a/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetReader.java b/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetReader.java
index 3591f0a..68afc29 100644
--- a/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetReader.java
+++ b/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetReader.java
@@ -33,6 +33,7 @@
*/
public final class BinaryKeysetReader implements KeysetReader {
private final InputStream inputStream;
+ private final boolean closeStreamAfterReading;
/**
* Static method to create a BinaryKeysetReader from an {@link InputStream}.
@@ -41,12 +42,13 @@
* BinaryKeysetReader#readEncrypted} is called.
*/
public static KeysetReader withInputStream(InputStream stream) {
- return new BinaryKeysetReader(stream);
+ return new BinaryKeysetReader(stream, /*closeStreamAfterReading=*/ false);
}
/** Static method to create a BinaryKeysetReader from a byte arrary. */
public static KeysetReader withBytes(final byte[] bytes) {
- return new BinaryKeysetReader(new ByteArrayInputStream(bytes));
+ return new BinaryKeysetReader(
+ new ByteArrayInputStream(bytes), /*closeStreamAfterReading=*/ true);
}
/**
@@ -56,20 +58,36 @@
* BinaryKeysetReader#readEncrypted} is called.
*/
public static KeysetReader withFile(File file) throws IOException {
- return new BinaryKeysetReader(new FileInputStream(file));
+ return new BinaryKeysetReader(new FileInputStream(file), /*closeStreamAfterReading=*/ true);
}
- private BinaryKeysetReader(InputStream stream) {
- inputStream = stream;
+ private BinaryKeysetReader(InputStream stream, boolean closeStreamAfterReading) {
+ this.inputStream = stream;
+ this.closeStreamAfterReading = closeStreamAfterReading;
}
@Override
public Keyset read() throws IOException {
- return Keyset.parseFrom(inputStream, ExtensionRegistryLite.getEmptyRegistry());
+ try {
+ Keyset keyset = Keyset.parseFrom(inputStream, ExtensionRegistryLite.getEmptyRegistry());
+ return keyset;
+ } finally {
+ if (closeStreamAfterReading) {
+ inputStream.close();
+ }
+ }
}
@Override
public EncryptedKeyset readEncrypted() throws IOException {
- return EncryptedKeyset.parseFrom(inputStream, ExtensionRegistryLite.getEmptyRegistry());
+ try {
+ EncryptedKeyset keyset =
+ EncryptedKeyset.parseFrom(inputStream, ExtensionRegistryLite.getEmptyRegistry());
+ return keyset;
+ } finally {
+ if (closeStreamAfterReading) {
+ inputStream.close();
+ }
+ }
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetWriter.java b/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetWriter.java
index bd90b12..f7ec632 100644
--- a/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetWriter.java
+++ b/java_src/src/main/java/com/google/crypto/tink/BinaryKeysetWriter.java
@@ -31,28 +31,42 @@
*/
public final class BinaryKeysetWriter implements KeysetWriter {
private final OutputStream outputStream;
+ private final boolean closeStreamAfterReading;
- private BinaryKeysetWriter(OutputStream stream) {
- outputStream = stream;
+ private BinaryKeysetWriter(OutputStream stream, boolean closeStreamAfterReading) {
+ this.outputStream = stream;
+ this.closeStreamAfterReading = closeStreamAfterReading;
}
/** Static method to create a BinaryKeysetWriter that writes to an {@link OutputStream}. */
public static KeysetWriter withOutputStream(OutputStream stream) {
- return new BinaryKeysetWriter(stream);
+ return new BinaryKeysetWriter(stream, /*closeStreamAfterReading=*/ false);
}
/** Static method to create a BinaryKeysetWriter that writes to a file. */
public static KeysetWriter withFile(File file) throws IOException {
- return new BinaryKeysetWriter(new FileOutputStream(file));
+ return new BinaryKeysetWriter(new FileOutputStream(file), /*closeStreamAfterReading=*/ true);
}
@Override
public void write(Keyset keyset) throws IOException {
- outputStream.write(keyset.toByteArray());
+ try {
+ keyset.writeTo(outputStream);
+ } finally {
+ if (closeStreamAfterReading) {
+ outputStream.close();
+ }
+ }
}
@Override
public void write(EncryptedKeyset keyset) throws IOException {
- outputStream.write(keyset.toByteArray());
+ try {
+ keyset.writeTo(outputStream);
+ } finally {
+ if (closeStreamAfterReading) {
+ outputStream.close();
+ }
+ }
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/JsonKeysetReader.java b/java_src/src/main/java/com/google/crypto/tink/JsonKeysetReader.java
index 99e9d36..365ee53 100644
--- a/java_src/src/main/java/com/google/crypto/tink/JsonKeysetReader.java
+++ b/java_src/src/main/java/com/google/crypto/tink/JsonKeysetReader.java
@@ -21,9 +21,7 @@
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.proto.KeyStatusType;
import com.google.crypto.tink.proto.Keyset;
-import com.google.crypto.tink.proto.Keyset.Key;
import com.google.crypto.tink.proto.KeysetInfo;
-import com.google.crypto.tink.proto.KeysetInfo.KeyInfo;
import com.google.crypto.tink.proto.OutputPrefixType;
import com.google.crypto.tink.subtle.Base64;
import com.google.protobuf.ByteString;
@@ -50,16 +48,19 @@
private final InputStream inputStream;
private final JSONObject json;
+ private final boolean closeStreamAfterReading;
private boolean urlSafeBase64 = false;
- private JsonKeysetReader(InputStream inputStream) {
+ private JsonKeysetReader(InputStream inputStream, boolean closeStreamAfterReading) {
this.inputStream = inputStream;
+ this.closeStreamAfterReading = closeStreamAfterReading;
json = null;
}
private JsonKeysetReader(JSONObject json) {
this.json = json;
this.inputStream = null;
+ this.closeStreamAfterReading = false;
}
/**
@@ -69,7 +70,7 @@
* JsonKeysetReader#readEncrypted} is called.
*/
public static KeysetReader withInputStream(InputStream input) throws IOException {
- return new JsonKeysetReader(input);
+ return new JsonKeysetReader(input, /*closeStreamAfterReading=*/ false);
}
/** Static method to create a JsonKeysetReader from an {@link JSONObject}. */
@@ -79,12 +80,13 @@
/** Static method to create a JsonKeysetReader from a string. */
public static JsonKeysetReader withString(String input) {
- return new JsonKeysetReader(new ByteArrayInputStream(input.getBytes(UTF_8)));
+ return new JsonKeysetReader(
+ new ByteArrayInputStream(input.getBytes(UTF_8)), /*closeStreamAfterReading=*/ true);
}
/** Static method to create a JsonKeysetReader from a byte array. */
public static JsonKeysetReader withBytes(final byte[] bytes) {
- return new JsonKeysetReader(new ByteArrayInputStream(bytes));
+ return new JsonKeysetReader(new ByteArrayInputStream(bytes), /*closeStreamAfterReading=*/ true);
}
/**
@@ -94,7 +96,7 @@
* JsonKeysetReader#readEncrypted} is called.
*/
public static JsonKeysetReader withFile(File file) throws IOException {
- return new JsonKeysetReader(new FileInputStream(file));
+ return new JsonKeysetReader(new FileInputStream(file), /*closeStreamAfterReading=*/ true);
}
/**
@@ -137,6 +139,10 @@
}
} catch (JSONException e) {
throw new IOException(e);
+ } finally {
+ if (inputStream != null && closeStreamAfterReading) {
+ inputStream.close();
+ }
}
}
@@ -151,6 +157,10 @@
}
} catch (JSONException e) {
throw new IOException(e);
+ } finally {
+ if (inputStream != null && closeStreamAfterReading) {
+ inputStream.close();
+ }
}
}
@@ -181,9 +191,9 @@
.build();
}
- private Key keyFromJson(JSONObject json) throws JSONException {
+ private Keyset.Key keyFromJson(JSONObject json) throws JSONException {
validateKey(json);
- return Key.newBuilder()
+ return Keyset.Key.newBuilder()
.setStatus(getStatus(json.getString("status")))
.setKeyId(json.getInt("keyId"))
.setOutputPrefixType(getOutputPrefixType(json.getString("outputPrefixType")))
@@ -191,7 +201,7 @@
.build();
}
- private KeysetInfo keysetInfoFromJson(JSONObject json) throws JSONException {
+ private static KeysetInfo keysetInfoFromJson(JSONObject json) throws JSONException {
KeysetInfo.Builder builder = KeysetInfo.newBuilder();
if (json.has("primaryKeyId")) {
builder.setPrimaryKeyId(json.getInt("primaryKeyId"));
@@ -205,8 +215,8 @@
return builder.build();
}
- private KeyInfo keyInfoFromJson(JSONObject json) throws JSONException {
- return KeyInfo.newBuilder()
+ private static KeysetInfo.KeyInfo keyInfoFromJson(JSONObject json) throws JSONException {
+ return KeysetInfo.KeyInfo.newBuilder()
.setStatus(getStatus(json.getString("status")))
.setKeyId(json.getInt("keyId"))
.setOutputPrefixType(getOutputPrefixType(json.getString("outputPrefixType")))
@@ -229,7 +239,7 @@
.build();
}
- private KeyStatusType getStatus(String status) throws JSONException {
+ private static KeyStatusType getStatus(String status) throws JSONException {
if (status.equals("ENABLED")) {
return KeyStatusType.ENABLED;
} else if (status.equals("DISABLED")) {
@@ -238,7 +248,7 @@
throw new JSONException("unknown status: " + status);
}
- private OutputPrefixType getOutputPrefixType(String type) throws JSONException {
+ private static OutputPrefixType getOutputPrefixType(String type) throws JSONException {
if (type.equals("TINK")) {
return OutputPrefixType.TINK;
} else if (type.equals("RAW")) {
@@ -251,7 +261,7 @@
throw new JSONException("unknown output prefix type: " + type);
}
- private KeyMaterialType getKeyMaterialType(String type) throws JSONException {
+ private static KeyMaterialType getKeyMaterialType(String type) throws JSONException {
if (type.equals("SYMMETRIC")) {
return KeyMaterialType.SYMMETRIC;
} else if (type.equals("ASYMMETRIC_PRIVATE")) {
@@ -264,19 +274,19 @@
throw new JSONException("unknown key material type: " + type);
}
- private void validateKeyset(JSONObject json) throws JSONException {
+ private static void validateKeyset(JSONObject json) throws JSONException {
if (!json.has("key") || json.getJSONArray("key").length() == 0) {
throw new JSONException("invalid keyset");
}
}
- private void validateEncryptedKeyset(JSONObject json) throws JSONException {
+ private static void validateEncryptedKeyset(JSONObject json) throws JSONException {
if (!json.has("encryptedKeyset")) {
throw new JSONException("invalid encrypted keyset");
}
}
- private void validateKey(JSONObject json) throws JSONException {
+ private static void validateKey(JSONObject json) throws JSONException {
if (!json.has("keyData")
|| !json.has("status")
|| !json.has("keyId")
@@ -285,7 +295,7 @@
}
}
- private void validateKeyData(JSONObject json) throws JSONException {
+ private static void validateKeyData(JSONObject json) throws JSONException {
if (!json.has("typeUrl") || !json.has("value") || !json.has("keyMaterialType")) {
throw new JSONException("invalid keyData");
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/JsonKeysetWriter.java b/java_src/src/main/java/com/google/crypto/tink/JsonKeysetWriter.java
index 30b4ec1..857e20c 100644
--- a/java_src/src/main/java/com/google/crypto/tink/JsonKeysetWriter.java
+++ b/java_src/src/main/java/com/google/crypto/tink/JsonKeysetWriter.java
@@ -19,9 +19,7 @@
import com.google.crypto.tink.proto.EncryptedKeyset;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.proto.Keyset;
-import com.google.crypto.tink.proto.Keyset.Key;
import com.google.crypto.tink.proto.KeysetInfo;
-import com.google.crypto.tink.proto.KeysetInfo.KeyInfo;
import com.google.crypto.tink.subtle.Base64;
import java.io.File;
import java.io.FileOutputStream;
@@ -49,7 +47,11 @@
outputStream = stream;
}
- /** Static method to create a JsonKeysetWriter that writes to an {@link OutputStream}. */
+ /**
+ * Static method to create a JsonKeysetWriter that writes to an {@link OutputStream}.
+ *
+ * <p>{@code stream} will be closed after the keyset is written.
+ */
public static KeysetWriter withOutputStream(OutputStream stream) {
return new JsonKeysetWriter(stream);
}
@@ -79,6 +81,8 @@
outputStream.write(toJson(keyset).toString(4).getBytes(UTF_8));
} catch (JSONException e) {
throw new IOException(e);
+ } finally {
+ outputStream.close();
}
}
@@ -88,9 +92,11 @@
outputStream.write(toJson(keyset).toString(4).getBytes(UTF_8));
} catch (JSONException e) {
throw new IOException(e);
+ } finally {
+ outputStream.close();
}
}
-
+
private long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
@@ -99,14 +105,14 @@
JSONObject json = new JSONObject();
json.put("primaryKeyId", toUnsignedLong(keyset.getPrimaryKeyId()));
JSONArray keys = new JSONArray();
- for (Key key : keyset.getKeyList()) {
+ for (Keyset.Key key : keyset.getKeyList()) {
keys.put(toJson(key));
}
json.put("key", keys);
return json;
}
- private JSONObject toJson(Key key) throws JSONException {
+ private JSONObject toJson(Keyset.Key key) throws JSONException {
return new JSONObject()
.put("keyData", toJson(key.getKeyData()))
.put("status", key.getStatus().name())
@@ -131,14 +137,14 @@
JSONObject json = new JSONObject();
json.put("primaryKeyId", toUnsignedLong(keysetInfo.getPrimaryKeyId()));
JSONArray keyInfos = new JSONArray();
- for (KeyInfo keyInfo : keysetInfo.getKeyInfoList()) {
+ for (KeysetInfo.KeyInfo keyInfo : keysetInfo.getKeyInfoList()) {
keyInfos.put(toJson(keyInfo));
}
json.put("keyInfo", keyInfos);
return json;
}
- private JSONObject toJson(KeyInfo keyInfo) throws JSONException {
+ private JSONObject toJson(KeysetInfo.KeyInfo keyInfo) throws JSONException {
return new JSONObject()
.put("typeUrl", keyInfo.getTypeUrl())
.put("status", keyInfo.getStatus().name())
diff --git a/java_src/src/main/java/com/google/crypto/tink/KeyTypeManager.java b/java_src/src/main/java/com/google/crypto/tink/KeyTypeManager.java
index fd7ec38..972b6b0 100644
--- a/java_src/src/main/java/com/google/crypto/tink/KeyTypeManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/KeyTypeManager.java
@@ -79,7 +79,7 @@
* Constructs a new KeyTypeManager.
*
* <p>Takes an arbitrary number of {@link PrimitiveFactory} objects as input. These will be used
- * and provided via {@link #createPrimitive} to the user.
+ * and provided via {@link #getPrimitive} to the user.
*
* @throws IllegalArgumentException if two of the passed in factories produce primitives of the
* same class.
diff --git a/java_src/src/main/java/com/google/crypto/tink/Registry.java b/java_src/src/main/java/com/google/crypto/tink/Registry.java
index a761a1b..1864b9b 100644
--- a/java_src/src/main/java/com/google/crypto/tink/Registry.java
+++ b/java_src/src/main/java/com/google/crypto/tink/Registry.java
@@ -26,6 +26,7 @@
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.Collections;
+import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -34,21 +35,21 @@
/**
* A global container of key managers and catalogues.
*
- * <p>Registry maps catalogue names to instances of {@link Catalogue} and each supported key type to
- * a corresponding {@link KeyManager} object, which "understands" the key type (i.e., the KeyManager
- * can instantiate the primitive corresponding to given key, or can generate new keys of the
- * supported key type). It holds also a {@link PrimitiveWrapper} for each supported primitive,
- * so that it can wrap a set of primitives (corresponding to a keyset) into a single primitive.
+ * <p>Registry maps each supported key type to a corresponding {@link KeyManager} object, which
+ * "understands" the key type (i.e., the KeyManager can instantiate the primitive corresponding to
+ * given key, or can generate new keys of the supported key type). It holds also a {@link
+ * PrimitiveWrapper} for each supported primitive, so that it can wrap a set of primitives
+ * (corresponding to a keyset) into a single primitive.
*
- * <p> Keeping KeyManagers for all primitives in a single Registry (rather than
- * having a separate KeyManager per primitive) enables modular construction of compound primitives
- * from "simple" ones, e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
+ * <p>Keeping KeyManagers for all primitives in a single Registry (rather than having a separate
+ * KeyManager per primitive) enables modular construction of compound primitives from "simple" ones,
+ * e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
*
* <p>Registry is initialized at startup, and is later used to instantiate primitives for given keys
* or keysets. Note that regular users will usually not work directly with Registry, but rather via
- * {@link Config} and {@link KeysetHandle#getPrimitive()}-methods, which in the background register
- * and query the Registry for specific KeyManagers and PrimitiveWrappers. Registry is public though,
- * to enable configurations with custom catalogues, primitives or KeyManagers.
+ * {@link TinkConfig} and {@link KeysetHandle#getPrimitive(Class)}-methods, which in the background
+ * register and query the Registry for specific KeyManagers and PrimitiveWrappers. Registry is
+ * public though, to enable configurations with custom catalogues, primitives or KeyManagers.
*
* <p>To initialize the Registry with all key managers:
*
@@ -62,8 +63,7 @@
* AeadConfig.register();
* }</pre>
*
- * <p>After the Registry has been initialized, one can use {@keysetHandle.getPrimitive} to get a
- * primitive. For example, to obtain an {@link Aead} primitive:
+ * <p>After the Registry has been initialized, one can use get a primitive as follows:
*
* <pre>{@code
* KeysetHandle keysetHandle = ...;
@@ -355,8 +355,8 @@
if (catalogue == null) {
throw new IllegalArgumentException("catalogue must be non-null.");
}
- if (catalogueMap.containsKey(catalogueName.toLowerCase())) {
- Catalogue<?> existing = catalogueMap.get(catalogueName.toLowerCase());
+ if (catalogueMap.containsKey(catalogueName.toLowerCase(Locale.US))) {
+ Catalogue<?> existing = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
if (!catalogue.getClass().equals(existing.getClass())) {
logger.warning(
"Attempted overwrite of a catalogueName catalogue for name " + catalogueName);
@@ -364,7 +364,7 @@
"catalogue for name " + catalogueName + " has been already registered");
}
}
- catalogueMap.put(catalogueName.toLowerCase(), catalogue);
+ catalogueMap.put(catalogueName.toLowerCase(Locale.US), catalogue);
}
/**
@@ -379,25 +379,25 @@
if (catalogueName == null) {
throw new IllegalArgumentException("catalogueName must be non-null.");
}
- Catalogue<?> catalogue = catalogueMap.get(catalogueName.toLowerCase());
+ Catalogue<?> catalogue = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
if (catalogue == null) {
String error = String.format("no catalogue found for %s. ", catalogueName);
- if (catalogueName.toLowerCase().startsWith("tinkaead")) {
+ if (catalogueName.toLowerCase(Locale.US).startsWith("tinkaead")) {
error += "Maybe call AeadConfig.register().";
}
- if (catalogueName.toLowerCase().startsWith("tinkdeterministicaead")) {
+ if (catalogueName.toLowerCase(Locale.US).startsWith("tinkdeterministicaead")) {
error += "Maybe call DeterministicAeadConfig.register().";
- } else if (catalogueName.toLowerCase().startsWith("tinkstreamingaead")) {
+ } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkstreamingaead")) {
error += "Maybe call StreamingAeadConfig.register().";
- } else if (catalogueName.toLowerCase().startsWith("tinkhybriddecrypt")
- || catalogueName.toLowerCase().startsWith("tinkhybridencrypt")) {
+ } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkhybriddecrypt")
+ || catalogueName.toLowerCase(Locale.US).startsWith("tinkhybridencrypt")) {
error += "Maybe call HybridConfig.register().";
- } else if (catalogueName.toLowerCase().startsWith("tinkmac")) {
+ } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkmac")) {
error += "Maybe call MacConfig.register().";
- } else if (catalogueName.toLowerCase().startsWith("tinkpublickeysign")
- || catalogueName.toLowerCase().startsWith("tinkpublickeyverify")) {
+ } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeysign")
+ || catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeyverify")) {
error += "Maybe call SignatureConfig.register().";
- } else if (catalogueName.toLowerCase().startsWith("tink")) {
+ } else if (catalogueName.toLowerCase(Locale.US).startsWith("tink")) {
error += "Maybe call TinkConfig.register().";
}
throw new GeneralSecurityException(error);
@@ -476,9 +476,7 @@
}
String typeUrl = manager.getKeyType();
ensureKeyManagerInsertable(typeUrl, manager.getClass(), newKeyAllowed);
- if (!keyManagerMap.containsKey(typeUrl)) {
- keyManagerMap.put(typeUrl, createContainerFor(manager));
- }
+ keyManagerMap.putIfAbsent(typeUrl, createContainerFor(manager));
newKeyAllowedMap.put(typeUrl, Boolean.valueOf(newKeyAllowed));
}
@@ -627,10 +625,9 @@
if (primitiveWrapperMap.containsKey(classObject)) {
@SuppressWarnings("unchecked") // We know that we only inserted objects of the correct type.
PrimitiveWrapper<P> existingWrapper =
- (PrimitiveWrapper<P>) (primitiveWrapperMap.get(classObject));
+ (PrimitiveWrapper<P>) primitiveWrapperMap.get(classObject);
if (!wrapper.getClass().equals(existingWrapper.getClass())) {
- logger.warning(
- "Attempted overwrite of a registered SetWrapper for type " + classObject.toString());
+ logger.warning("Attempted overwrite of a registered SetWrapper for type " + classObject);
throw new GeneralSecurityException(
String.format(
"SetWrapper for primitive (%s) is already registered to be %s, "
@@ -758,8 +755,8 @@
}
/**
- * Method to derive a key, using the given {@param keyTemplate}, with the randomness as provided
- * by the second argument.
+ * Method to derive a key, using the given {@code keyTemplate}, with the randomness as provided by
+ * the second argument.
*
* <p>This method is on purpose not in the public interface. Calling it twice using different key
* templates and the same randomness can completely destroy any security in a system, so we
@@ -1051,4 +1048,6 @@
KeyManagerContainer container = getKeyManagerContainerOrThrow(keyData.getTypeUrl());
return container.parseKey(keyData.getValue());
}
+
+ private Registry() {}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/AeadConfig.java b/java_src/src/main/java/com/google/crypto/tink/aead/AeadConfig.java
index d311175..3e27207 100644
--- a/java_src/src/main/java/com/google/crypto/tink/aead/AeadConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/AeadConfig.java
@@ -16,14 +16,14 @@
package com.google.crypto.tink.aead;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.mac.MacConfig;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.Aead} key types supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.Aead} key types supported in a particular release of
+ * Tink.
*
* <p>To register all Aead key types provided in the latest Tink version one can do:
*
@@ -46,18 +46,17 @@
public static final String XCHACHA20_POLY1305_TYPE_URL =
new XChaCha20Poly1305KeyManager().getKeyType();
- /** @deprecated */
+ /** @deprecated use {@link #register} */
@Deprecated public static final RegistryConfig TINK_1_0_0 = RegistryConfig.getDefaultInstance();
/**
- * @deprecated
+ * @deprecated use {@link #register}
* @since 1.1.0
*/
@Deprecated public static final RegistryConfig TINK_1_1_0 = TINK_1_0_0;
/**
- * * @deprecated
- *
+ * @deprecated use {@link #register}
* @since 1.2.0
*/
@Deprecated public static final RegistryConfig LATEST = TINK_1_0_0;
@@ -71,7 +70,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} and {@link com.google.crypto.tink.KeyManager} needed to
* handle Aead key types supported in Tink.
*
@@ -86,7 +85,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} and {@link com.google.crypto.tink.KeyManager} needed to
* handle Aead key types supported in Tink.
*
@@ -120,4 +119,6 @@
public static void registerStandardKeyTypes() throws GeneralSecurityException {
register();
}
+
+ private AeadConfig() {}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/AesCtrHmacAeadKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/aead/AesCtrHmacAeadKeyManager.java
index eee19c7..316d23c 100644
--- a/java_src/src/main/java/com/google/crypto/tink/aead/AesCtrHmacAeadKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/AesCtrHmacAeadKeyManager.java
@@ -79,6 +79,8 @@
@Override
public void validateKey(AesCtrHmacAeadKey key) throws GeneralSecurityException {
Validators.validateVersion(key.getVersion(), getVersion());
+ new AesCtrKeyManager().validateKey(key.getAesCtrKey());
+ new HmacKeyManager().validateKey(key.getHmacKey());
}
@Override
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/aead/BUILD.bazel
index bee2468..fed96bd 100644
--- a/java_src/src/main/java/com/google/crypto/tink/aead/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/BUILD.bazel
@@ -1,8 +1,443 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "aes_gcm_key_manager",
+ srcs = ["AesGcmKeyManager.java"],
+ deps = [
+ "//proto:aes_gcm_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aead_key_templates",
+ srcs = ["AeadKeyTemplates.java"],
+ deps = [
+ ":aes_ctr_hmac_aead_key_manager",
+ ":aes_eax_key_manager",
+ ":aes_gcm_key_manager",
+ ":cha_cha20_poly1305_key_manager",
+ ":kms_aead_key_manager",
+ ":kms_envelope_aead_key_manager",
+ ":x_cha_cha20_poly1305_key_manager",
+ "//proto:aes_ctr_hmac_aead_java_proto",
+ "//proto:aes_ctr_java_proto",
+ "//proto:aes_eax_java_proto",
+ "//proto:aes_gcm_java_proto",
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:kms_aead_java_proto",
+ "//proto:kms_envelope_java_proto",
+ "//proto:tink_java_proto",
+ ],
+)
+
+java_library(
+ name = "aes_ctr_hmac_aead_key_manager",
+ srcs = ["AesCtrHmacAeadKeyManager.java"],
+ deps = [
+ ":aes_ctr_key_manager",
+ "//proto:aes_ctr_hmac_aead_java_proto",
+ "//proto:aes_ctr_java_proto",
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/mac:hmac_key_manager",
+ "//src/main/java/com/google/crypto/tink/subtle:encrypt_then_authenticate",
+ "//src/main/java/com/google/crypto/tink/subtle:ind_cpa_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aead_factory",
+ srcs = ["AeadFactory.java"],
+ deps = [
+ ":aead_wrapper",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "kms_aead_key_manager",
+ srcs = ["KmsAeadKeyManager.java"],
+ deps = [
+ "//proto:kms_aead_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink:kms_clients",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "kms_envelope_aead",
+ srcs = ["KmsEnvelopeAead.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "x_cha_cha20_poly1305_key_manager",
+ srcs = ["XChaCha20Poly1305KeyManager.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//proto:xchacha20_poly1305_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "//src/main/java/com/google/crypto/tink/subtle:x_cha_cha20_poly1305",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aead_wrapper",
+ srcs = ["AeadWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "kms_envelope_aead_key_manager",
+ srcs = ["KmsEnvelopeAeadKeyManager.java"],
+ deps = [
+ ":kms_envelope_aead",
+ "//proto:kms_envelope_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink:kms_clients",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aes_ctr_key_manager",
+ srcs = ["AesCtrKeyManager.java"],
+ deps = [
+ "//proto:aes_ctr_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_jce_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:ind_cpa_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "cha_cha20_poly1305_key_manager",
+ srcs = ["ChaCha20Poly1305KeyManager.java"],
+ deps = [
+ "//proto:chacha20_poly1305_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:cha_cha20_poly1305",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aes_eax_key_manager",
+ srcs = ["AesEaxKeyManager.java"],
+ deps = [
+ "//proto:aes_eax_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_eax_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aead_config",
+ srcs = ["AeadConfig.java"],
+ deps = [
+ ":aead_wrapper",
+ ":aes_ctr_hmac_aead_key_manager",
+ ":aes_eax_key_manager",
+ ":aes_gcm_key_manager",
+ ":cha_cha20_poly1305_key_manager",
+ ":kms_aead_key_manager",
+ ":kms_envelope_aead_key_manager",
+ ":x_cha_cha20_poly1305_key_manager",
+ "//proto:config_java_proto",
+ "//src/main/java/com/google/crypto/tink/mac:mac_config",
+ ],
+)
+
+# Android libraries
+
+android_library(
+ name = "aes_gcm_key_manager-android",
+ srcs = ["AesGcmKeyManager.java"],
+ deps = [
+ "//proto:aes_gcm_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aead_key_templates-android",
+ srcs = ["AeadKeyTemplates.java"],
+ deps = [
+ ":aes_ctr_hmac_aead_key_manager-android",
+ ":aes_eax_key_manager-android",
+ ":aes_gcm_key_manager-android",
+ ":cha_cha20_poly1305_key_manager-android",
+ ":kms_aead_key_manager-android",
+ ":kms_envelope_aead_key_manager-android",
+ ":x_cha_cha20_poly1305_key_manager-android",
+ "//proto:aes_ctr_hmac_aead_java_proto_lite",
+ "//proto:aes_ctr_java_proto_lite",
+ "//proto:aes_eax_java_proto_lite",
+ "//proto:aes_gcm_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:kms_aead_java_proto_lite",
+ "//proto:kms_envelope_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+android_library(
+ name = "aes_ctr_hmac_aead_key_manager-android",
+ srcs = ["AesCtrHmacAeadKeyManager.java"],
+ deps = [
+ ":aes_ctr_key_manager-android",
+ "//proto:aes_ctr_hmac_aead_java_proto_lite",
+ "//proto:aes_ctr_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/mac:hmac_key_manager-android",
+ "//src/main/java/com/google/crypto/tink/subtle:encrypt_then_authenticate",
+ "//src/main/java/com/google/crypto/tink/subtle:ind_cpa_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aead_factory-android",
+ srcs = ["AeadFactory.java"],
+ deps = [
+ ":aead_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "kms_aead_key_manager-android",
+ srcs = ["KmsAeadKeyManager.java"],
+ deps = [
+ "//proto:kms_aead_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink:kms_clients",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "kms_envelope_aead-android",
+ srcs = ["KmsEnvelopeAead.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "x_cha_cha20_poly1305_key_manager-android",
+ srcs = ["XChaCha20Poly1305KeyManager.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//proto:xchacha20_poly1305_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "//src/main/java/com/google/crypto/tink/subtle:x_cha_cha20_poly1305",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aead_wrapper-android",
+ srcs = ["AeadWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "kms_envelope_aead_key_manager-android",
+ srcs = ["KmsEnvelopeAeadKeyManager.java"],
+ deps = [
+ ":kms_envelope_aead-android",
+ "//proto:kms_envelope_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink:kms_clients",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aes_ctr_key_manager-android",
+ srcs = ["AesCtrKeyManager.java"],
+ deps = [
+ "//proto:aes_ctr_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_jce_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:ind_cpa_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "cha_cha20_poly1305_key_manager-android",
+ srcs = ["ChaCha20Poly1305KeyManager.java"],
+ deps = [
+ "//proto:chacha20_poly1305_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:cha_cha20_poly1305",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aes_eax_key_manager-android",
+ srcs = ["AesEaxKeyManager.java"],
+ deps = [
+ "//proto:aes_eax_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_eax_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aead_config-android",
+ srcs = ["AeadConfig.java"],
+ deps = [
+ ":aead_wrapper-android",
+ ":aes_ctr_hmac_aead_key_manager-android",
+ ":aes_eax_key_manager-android",
+ ":aes_gcm_key_manager-android",
+ ":cha_cha20_poly1305_key_manager-android",
+ ":kms_aead_key_manager-android",
+ ":kms_envelope_aead_key_manager-android",
+ ":x_cha_cha20_poly1305_key_manager-android",
+ "//proto:config_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/mac:mac_config-android",
+ ],
+)
+
+# Deprecated rules, will be removed soon.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AeadFactory.java b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AeadFactory.java
new file mode 100644
index 0000000..8b79fbd
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AeadFactory.java
@@ -0,0 +1,34 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.aead.subtle;
+
+import com.google.crypto.tink.Aead;
+import com.google.errorprone.annotations.Immutable;
+import java.security.GeneralSecurityException;
+
+/** Provides AEAD instances with a specific raw key. */
+@Immutable
+public interface AeadFactory {
+ /** Returns the size of the AEAD key in bytes. */
+ public int getKeySizeInBytes();
+
+ /**
+ * Creates a new {@code Aead}-primitive that uses the key material given in {@code symmetricKey},
+ * which must be of length {@link #getKeySizeInBytes}.
+ *
+ * @return the newly created {@code Aead}-primitive.
+ */
+ public Aead createAead(final byte[] symmetricKey) throws GeneralSecurityException;
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AesGcmFactory.java b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AesGcmFactory.java
new file mode 100644
index 0000000..37de892
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/AesGcmFactory.java
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.aead.subtle;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.subtle.AesGcmJce;
+import com.google.errorprone.annotations.Immutable;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+
+/** An {@link AeadFactory} that creates new instances of AES-GCM from raw keys */
+@Immutable
+public final class AesGcmFactory implements AeadFactory {
+ private final int keySizeInBytes;
+
+ public AesGcmFactory(int keySizeInBytes) throws GeneralSecurityException {
+ this.keySizeInBytes = validateAesKeySize(keySizeInBytes);
+ }
+
+ @Override
+ public int getKeySizeInBytes() {
+ return keySizeInBytes;
+ }
+
+ @Override
+ public Aead createAead(final byte[] symmetricKey) throws GeneralSecurityException {
+ if (symmetricKey.length != getKeySizeInBytes()) {
+ throw new GeneralSecurityException(
+ String.format(
+ "Symmetric key has incorrect length; expected %s, but got %s",
+ getKeySizeInBytes(), symmetricKey.length));
+ }
+ return new AesGcmJce(symmetricKey);
+ }
+
+ /** @throws InvalidAlgorithmParameterException if {@code sizeInBytes} is not supported. */
+ private static int validateAesKeySize(int sizeInBytes) throws InvalidAlgorithmParameterException {
+ if (sizeInBytes != 16 && sizeInBytes != 32) {
+ throw new InvalidAlgorithmParameterException(
+ String.format("Invalid AES key size, expected 16 or 32, but got %d", sizeInBytes));
+ }
+ return sizeInBytes;
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/aead/subtle/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/BUILD.bazel
new file mode 100644
index 0000000..2f82d99
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/aead/subtle/BUILD.bazel
@@ -0,0 +1,27 @@
+load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+
+licenses(["notice"])
+
+package(default_visibility = ["//:__subpackages__"])
+
+java_library(
+ name = "aead_factory",
+ srcs = ["AeadFactory.java"],
+ javacopts = JAVACOPTS_OSS,
+ deps = [
+ "//src/main/java/com/google/crypto/tink:aead",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+java_library(
+ name = "aes_gcm_factory",
+ srcs = ["AesGcmFactory.java"],
+ javacopts = JAVACOPTS_OSS,
+ deps = [
+ ":aead_factory",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_jce",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/annotations/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/annotations/BUILD.bazel
index eb925f7..44c5b41 100644
--- a/java_src/src/main/java/com/google/crypto/tink/annotations/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/annotations/BUILD.bazel
@@ -2,7 +2,14 @@
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "alpha",
+ srcs = ["Alpha.java"],
+)
+
+# Deprecated rules, will be deleted soon
java_library(
name = "annotations",
diff --git a/java_src/src/main/java/com/google/crypto/tink/config/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/config/BUILD.bazel
index f145059..3d4f4e2 100644
--- a/java_src/src/main/java/com/google/crypto/tink/config/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/config/BUILD.bazel
@@ -1,8 +1,37 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "tink_config",
+ srcs = ["TinkConfig.java"],
+ deps = [
+ "//proto:config_java_proto",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_config",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_config",
+ "//src/main/java/com/google/crypto/tink/prf:prf_config",
+ "//src/main/java/com/google/crypto/tink/signature:signature_config",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config",
+ ],
+)
+
+android_library(
+ name = "tink_config-android",
+ srcs = ["TinkConfig.java"],
+ deps = [
+ "//proto:config_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_config-android",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_config-android",
+ "//src/main/java/com/google/crypto/tink/prf:prf_config-android",
+ "//src/main/java/com/google/crypto/tink/signature:signature_config-android",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config-android",
+ ],
+)
+
+# Deprecated rules, will be removed soon
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/config/TinkConfig.java b/java_src/src/main/java/com/google/crypto/tink/config/TinkConfig.java
index f2552a3..3919f83 100644
--- a/java_src/src/main/java/com/google/crypto/tink/config/TinkConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/config/TinkConfig.java
@@ -98,7 +98,9 @@
public static void register() throws GeneralSecurityException {
DeterministicAeadConfig.register();
HybridConfig.register(); // includes Aead and Mac
- SignatureConfig.register();
PrfConfig.register();
+ SignatureConfig.register();
+ StreamingAeadConfig.register();
+ // place holder for KeyDerivationConfig. DO NOT EDIT.
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/daead/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/daead/BUILD.bazel
index 8fda110..ea0d75d 100644
--- a/java_src/src/main/java/com/google/crypto/tink/daead/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/daead/BUILD.bazel
@@ -1,8 +1,135 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "deterministic_aead_key_templates",
+ srcs = ["DeterministicAeadKeyTemplates.java"],
+ deps = [
+ ":aes_siv_key_manager",
+ "//proto:aes_siv_java_proto",
+ "//proto:tink_java_proto",
+ ],
+)
+
+android_library(
+ name = "deterministic_aead_key_templates-android",
+ srcs = ["DeterministicAeadKeyTemplates.java"],
+ deps = [
+ ":aes_siv_key_manager-android",
+ "//proto:aes_siv_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "deterministic_aead_factory",
+ srcs = ["DeterministicAeadFactory.java"],
+ deps = [
+ ":deterministic_aead_wrapper",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+android_library(
+ name = "deterministic_aead_factory-android",
+ srcs = ["DeterministicAeadFactory.java"],
+ deps = [
+ ":deterministic_aead_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+java_library(
+ name = "deterministic_aead_config",
+ srcs = ["DeterministicAeadConfig.java"],
+ deps = [
+ ":aes_siv_key_manager",
+ ":deterministic_aead_wrapper",
+ "//proto:config_java_proto",
+ ],
+)
+
+android_library(
+ name = "deterministic_aead_config-android",
+ srcs = ["DeterministicAeadConfig.java"],
+ deps = [
+ ":aes_siv_key_manager-android",
+ ":deterministic_aead_wrapper-android",
+ "//proto:config_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "deterministic_aead_wrapper",
+ srcs = ["DeterministicAeadWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "deterministic_aead_wrapper-android",
+ srcs = ["DeterministicAeadWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "aes_siv_key_manager",
+ srcs = ["AesSivKeyManager.java"],
+ deps = [
+ "//proto:aes_siv_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_siv",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aes_siv_key_manager-android",
+ srcs = ["AesSivKeyManager.java"],
+ deps = [
+ "//proto:aes_siv_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_siv",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+# Deprecated rules, will be removed soon.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/daead/DeterministicAeadConfig.java b/java_src/src/main/java/com/google/crypto/tink/daead/DeterministicAeadConfig.java
index b81a9e1..a6c9e15 100644
--- a/java_src/src/main/java/com/google/crypto/tink/daead/DeterministicAeadConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/daead/DeterministicAeadConfig.java
@@ -16,13 +16,13 @@
package com.google.crypto.tink.daead;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.DeterministicAead} key types supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.DeterministicAead} key types supported in a particular
+ * release of Tink.
*
* <p>To register all DeterministicAead key types provided in the latest Tink version one can do:
*
@@ -31,23 +31,21 @@
* }</pre>
*
* <p>For more information on how to obtain and use instances of DeterministicAead, see {@link
- * DeterministicAeadFactory}.
+ * com.google.crypto.tink.KeysetHandle#getPrimitive}.
*
* @since 1.1.0
*/
public final class DeterministicAeadConfig {
public static final String AES_SIV_TYPE_URL = new AesSivKeyManager().getKeyType();
- /** @deprecated */
- @Deprecated
- public static final RegistryConfig TINK_1_1_0 = RegistryConfig.getDefaultInstance();
+ /** @deprecated use {@link #register} */
+ @Deprecated public static final RegistryConfig TINK_1_1_0 = RegistryConfig.getDefaultInstance();
/**
- * @deprecated
+ * @deprecated use {@link #register}
* @since 1.2.0
*/
- @Deprecated
- public static final RegistryConfig LATEST = RegistryConfig.getDefaultInstance();
+ @Deprecated public static final RegistryConfig LATEST = RegistryConfig.getDefaultInstance();
static {
try {
@@ -58,7 +56,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle DeterministicAead key types supported in
* Tink.
*
@@ -73,7 +71,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle DeterministicAead key types supported in
* Tink.
*
@@ -83,4 +81,6 @@
AesSivKeyManager.register(/* newKeyAllowed = */ true);
DeterministicAeadWrapper.register();
}
+
+ private DeterministicAeadConfig() {}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/hybrid/BUILD.bazel
index 6b23b3f..5c4cd56 100644
--- a/java_src/src/main/java/com/google/crypto/tink/hybrid/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/BUILD.bazel
@@ -1,8 +1,339 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "hybrid_decrypt_config",
+ srcs = ["HybridDecryptConfig.java"],
+ deps = [
+ ":hybrid_config",
+ "//src/main/java/com/google/crypto/tink:config",
+ ],
+)
+
+java_library(
+ name = "hybrid_encrypt_wrapper",
+ srcs = ["HybridEncryptWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "hybrid_decrypt_wrapper",
+ srcs = ["HybridDecryptWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "ecies_aead_hkdf_public_key_manager",
+ srcs = ["EciesAeadHkdfPublicKeyManager.java"],
+ deps = [
+ ":hybrid_util",
+ ":registry_ecies_aead_hkdf_dem_helper",
+ "//proto:ecies_aead_hkdf_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "registry_ecies_aead_hkdf_dem_helper",
+ srcs = ["RegistryEciesAeadHkdfDemHelper.java"],
+ deps = [
+ "//proto:aes_ctr_hmac_aead_java_proto",
+ "//proto:aes_ctr_java_proto",
+ "//proto:aes_gcm_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "hybrid_config",
+ srcs = ["HybridConfig.java"],
+ deps = [
+ ":ecies_aead_hkdf_private_key_manager",
+ ":ecies_aead_hkdf_public_key_manager",
+ ":hybrid_decrypt_wrapper",
+ ":hybrid_encrypt_wrapper",
+ "//proto:config_java_proto",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config",
+ ],
+)
+
+java_library(
+ name = "hybrid_key_templates",
+ srcs = ["HybridKeyTemplates.java"],
+ deps = [
+ ":ecies_aead_hkdf_private_key_manager",
+ "//proto:common_java_proto",
+ "//proto:ecies_aead_hkdf_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink/aead:aead_key_templates",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "ecies_aead_hkdf_private_key_manager",
+ srcs = ["EciesAeadHkdfPrivateKeyManager.java"],
+ deps = [
+ ":ecies_aead_hkdf_public_key_manager",
+ ":hybrid_util",
+ ":registry_ecies_aead_hkdf_dem_helper",
+ "//proto:common_java_proto",
+ "//proto:ecies_aead_hkdf_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/aead:aes_ctr_hmac_aead_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:aes_gcm_key_manager",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "hybrid_util",
+ srcs = ["HybridUtil.java"],
+ deps = [
+ "//proto:common_java_proto",
+ "//proto:ecies_aead_hkdf_java_proto",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+java_library(
+ name = "hybrid_decrypt_factory",
+ srcs = ["HybridDecryptFactory.java"],
+ deps = [
+ ":hybrid_decrypt_wrapper",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "hybrid_encrypt_factory",
+ srcs = ["HybridEncryptFactory.java"],
+ deps = [
+ ":hybrid_encrypt_wrapper",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "hybrid_encrypt_config",
+ srcs = ["HybridEncryptConfig.java"],
+ deps = [
+ ":hybrid_config",
+ "//src/main/java/com/google/crypto/tink:config",
+ ],
+)
+
+# Android libraries
+
+android_library(
+ name = "hybrid_decrypt_config-android",
+ srcs = ["HybridDecryptConfig.java"],
+ deps = [
+ ":hybrid_config-android",
+ "//src/main/java/com/google/crypto/tink:config-android",
+ ],
+)
+
+android_library(
+ name = "hybrid_encrypt_wrapper-android",
+ srcs = ["HybridEncryptWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "hybrid_decrypt_wrapper-android",
+ srcs = ["HybridDecryptWrapper.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "ecies_aead_hkdf_public_key_manager-android",
+ srcs = ["EciesAeadHkdfPublicKeyManager.java"],
+ deps = [
+ ":hybrid_util-android",
+ ":registry_ecies_aead_hkdf_dem_helper-android",
+ "//proto:ecies_aead_hkdf_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "registry_ecies_aead_hkdf_dem_helper-android",
+ srcs = ["RegistryEciesAeadHkdfDemHelper.java"],
+ deps = [
+ "//proto:aes_ctr_hmac_aead_java_proto_lite",
+ "//proto:aes_ctr_java_proto_lite",
+ "//proto:aes_gcm_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config-android",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "hybrid_config-android",
+ srcs = ["HybridConfig.java"],
+ deps = [
+ ":ecies_aead_hkdf_private_key_manager-android",
+ ":ecies_aead_hkdf_public_key_manager-android",
+ ":hybrid_decrypt_wrapper-android",
+ ":hybrid_encrypt_wrapper-android",
+ "//proto:config_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config-android",
+ ],
+)
+
+android_library(
+ name = "hybrid_key_templates-android",
+ srcs = ["HybridKeyTemplates.java"],
+ deps = [
+ ":ecies_aead_hkdf_private_key_manager-android",
+ "//proto:common_java_proto_lite",
+ "//proto:ecies_aead_hkdf_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/aead:aead_key_templates-android",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "ecies_aead_hkdf_private_key_manager-android",
+ srcs = ["EciesAeadHkdfPrivateKeyManager.java"],
+ deps = [
+ ":ecies_aead_hkdf_public_key_manager-android",
+ ":hybrid_util-android",
+ ":registry_ecies_aead_hkdf_dem_helper-android",
+ "//proto:common_java_proto_lite",
+ "//proto:ecies_aead_hkdf_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/aead:aes_ctr_hmac_aead_key_manager-android",
+ "//src/main/java/com/google/crypto/tink/aead:aes_gcm_key_manager-android",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "hybrid_util-android",
+ srcs = ["HybridUtil.java"],
+ deps = [
+ "//proto:common_java_proto_lite",
+ "//proto:ecies_aead_hkdf_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ ],
+)
+
+android_library(
+ name = "hybrid_decrypt_factory-android",
+ srcs = ["HybridDecryptFactory.java"],
+ deps = [
+ ":hybrid_decrypt_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "hybrid_encrypt_factory-android",
+ srcs = ["HybridEncryptFactory.java"],
+ deps = [
+ ":hybrid_encrypt_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "hybrid_encrypt_config-android",
+ srcs = ["HybridEncryptConfig.java"],
+ deps = [
+ ":hybrid_config-android",
+ "//src/main/java/com/google/crypto/tink:config-android",
+ ],
+)
+
+# Deprecate rules, will be removed soon.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPrivateKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPrivateKeyManager.java
index 375d8f0..f0a4a4d 100644
--- a/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPrivateKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPrivateKeyManager.java
@@ -18,6 +18,7 @@
import com.google.crypto.tink.HybridDecrypt;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.PrivateKeyTypeManager;
import com.google.crypto.tink.Registry;
import com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager;
@@ -55,7 +56,8 @@
super(
EciesAeadHkdfPrivateKey.class,
EciesAeadHkdfPublicKey.class,
- new PrimitiveFactory<HybridDecrypt, EciesAeadHkdfPrivateKey>(HybridDecrypt.class) {
+ new KeyTypeManager.PrimitiveFactory<HybridDecrypt, EciesAeadHkdfPrivateKey>(
+ HybridDecrypt.class) {
@Override
public HybridDecrypt getPrimitive(EciesAeadHkdfPrivateKey recipientKeyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPublicKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPublicKeyManager.java
index 9975511..9d4f698 100644
--- a/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPublicKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/EciesAeadHkdfPublicKeyManager.java
@@ -40,7 +40,8 @@
public EciesAeadHkdfPublicKeyManager() {
super(
EciesAeadHkdfPublicKey.class,
- new PrimitiveFactory<HybridEncrypt, EciesAeadHkdfPublicKey>(HybridEncrypt.class) {
+ new KeyTypeManager.PrimitiveFactory<HybridEncrypt, EciesAeadHkdfPublicKey>(
+ HybridEncrypt.class) {
@Override
public HybridEncrypt getPrimitive(EciesAeadHkdfPublicKey recipientKeyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/HybridConfig.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/HybridConfig.java
index fa268d1..9f38f57 100644
--- a/java_src/src/main/java/com/google/crypto/tink/hybrid/HybridConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/HybridConfig.java
@@ -16,15 +16,14 @@
package com.google.crypto.tink.hybrid;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.aead.AeadConfig;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.HybridEncrypt} and {@link com.google.crypto.tink.HybridDecrypt} key types
- * supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.HybridEncrypt} and {@link
+ * com.google.crypto.tink.HybridDecrypt} key types supported in a particular release of Tink.
*
* <p>To register all HybridEncrypt and HybridDecrypt key types provided in the latest Tink version
* one can do:
@@ -67,7 +66,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle HybridDecrypt and HybridEncrypt key types
* supported in Tink.
*
@@ -83,7 +82,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle HybridDecrypt and HybridEncrypt key types
* supported in Tink.
*
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/BUILD.bazel
new file mode 100644
index 0000000..af6627c
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/BUILD.bazel
@@ -0,0 +1,32 @@
+licenses(["notice"])
+
+package(default_visibility = ["//:__subpackages__"])
+
+java_library(
+ name = "rsa_kem_hybrid_encrypt",
+ srcs = ["RsaKemHybridEncrypt.java"],
+ deps = [
+ ":rsa_kem",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink/aead/subtle:aead_factory",
+ "//src/main/java/com/google/crypto/tink/subtle:hkdf",
+ ],
+)
+
+java_library(
+ name = "rsa_kem",
+ srcs = ["RsaKem.java"],
+)
+
+java_library(
+ name = "rsa_kem_hybrid_decrypt",
+ srcs = ["RsaKemHybridDecrypt.java"],
+ deps = [
+ ":rsa_kem",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink/aead/subtle:aead_factory",
+ "//src/main/java/com/google/crypto/tink/subtle:hkdf",
+ ],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKem.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKem.java
new file mode 100644
index 0000000..58614db
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKem.java
@@ -0,0 +1,97 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+class RsaKem {
+ static final byte[] EMPTY_AAD = new byte[0];
+ static final int MIN_RSA_KEY_LENGTH_BITS = 2048;
+
+ private RsaKem() {}
+
+ static void validateRsaModulus(BigInteger mod) throws GeneralSecurityException {
+ if (mod.bitLength() < MIN_RSA_KEY_LENGTH_BITS) {
+ throw new GeneralSecurityException(
+ String.format(
+ "RSA key must be of at least size %d bits, but got %d",
+ MIN_RSA_KEY_LENGTH_BITS, mod.bitLength()));
+ }
+ }
+
+ static int bigIntSizeInBytes(BigInteger mod) {
+ return (mod.bitLength() + 7) / 8;
+ }
+
+ /**
+ * Converts {@code bigInt} to a fixed-size byte array, by taking away at most one leading zero
+ * (the sign byte), or adding leading zeros.
+ */
+ static byte[] bigIntToByteArray(BigInteger bigInt, int size) {
+ byte[] value = bigInt.toByteArray();
+ if (value.length == size) {
+ return value;
+ }
+
+ byte[] result = new byte[size];
+ if (value.length == result.length + 1) {
+ if (value[0] != 0) {
+ throw new IllegalArgumentException(
+ "Value is one-byte longer than the expected size, but its first byte is not 0");
+ }
+ System.arraycopy(value, 1, result, 0, result.length);
+ } else if (value.length < result.length) {
+ System.arraycopy(value, 0, result, result.length - value.length, value.length);
+ } else {
+ throw new IllegalArgumentException(
+ String.format(
+ "Value has invalid length, must be of length at most (%d + 1), but" + " got %d",
+ size, value.length));
+ }
+ return result;
+ }
+
+ /**
+ * Generates a random BigInteger in (0, max) (excluding 0 and max) and converts the result to a
+ * byte array having the same length as max.
+ */
+ static byte[] generateSecret(BigInteger max) {
+ int maxSizeInBytes = bigIntSizeInBytes(max);
+ Random rand = new SecureRandom();
+ BigInteger r;
+ do {
+ r = new BigInteger(max.bitLength(), rand);
+ } while (r.signum() <= 0 || r.compareTo(max) >= 0);
+
+ return bigIntToByteArray(r, maxSizeInBytes);
+ }
+
+ static KeyPair generateRsaKeyPair(int keySize) {
+ KeyPairGenerator rsaGenerator;
+ try {
+ rsaGenerator = KeyPairGenerator.getInstance("RSA");
+ rsaGenerator.initialize(keySize);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("No support for RSA algorithm.", e);
+ }
+ return rsaGenerator.generateKeyPair();
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecrypt.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecrypt.java
new file mode 100644
index 0000000..a2b9285
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecrypt.java
@@ -0,0 +1,81 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.HybridDecrypt;
+import com.google.crypto.tink.aead.subtle.AeadFactory;
+import com.google.crypto.tink.subtle.Hkdf;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.interfaces.RSAPrivateKey;
+import javax.crypto.Cipher;
+
+/**
+ * Hybrid encryption with RSA-KEM as defined in Shoup's ISO standard proposal as KEM, and AEAD as
+ * DEM and HKDF as KDF.
+ *
+ * <p>Shoup's ISO standard proposal is available at https://www.shoup.net/iso/std6.pdf.
+ */
+public final class RsaKemHybridDecrypt implements HybridDecrypt {
+ private final RSAPrivateKey recipientPrivateKey;
+ private final String hkdfHmacAlgo;
+ private final byte[] hkdfSalt;
+ private final AeadFactory aeadFactory;
+
+ public RsaKemHybridDecrypt(
+ final RSAPrivateKey recipientPrivateKey,
+ String hkdfHmacAlgo,
+ final byte[] hkdfSalt,
+ AeadFactory aeadFactory)
+ throws GeneralSecurityException {
+ RsaKem.validateRsaModulus(recipientPrivateKey.getModulus());
+ this.recipientPrivateKey = recipientPrivateKey;
+ this.hkdfSalt = hkdfSalt;
+ this.hkdfHmacAlgo = hkdfHmacAlgo;
+ this.aeadFactory = aeadFactory;
+ }
+
+ @Override
+ public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo)
+ throws GeneralSecurityException {
+ int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus());
+ if (ciphertext.length < modSizeInBytes) {
+ throw new GeneralSecurityException(
+ String.format(
+ "Ciphertext must be of at least size %d bytes, but got %d",
+ modSizeInBytes, ciphertext.length));
+ }
+
+ // Decrypt the token to obtain the raw shared secret.
+ ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext);
+ byte[] token = new byte[modSizeInBytes];
+ cipherBuffer.get(token);
+ Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding");
+ rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey);
+ byte[] sharedSecret = rsaCipher.doFinal(token);
+
+ // KDF: derive a DEM key from the shared secret, salt, and contextInfo.
+ byte[] demKey =
+ Hkdf.computeHkdf(
+ hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes());
+
+ // DEM: decrypt the payload.
+ Aead aead = aeadFactory.createAead(demKey);
+ byte[] demPayload = new byte[cipherBuffer.remaining()];
+ cipherBuffer.get(demPayload);
+ return aead.decrypt(demPayload, RsaKem.EMPTY_AAD);
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncrypt.java b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncrypt.java
new file mode 100644
index 0000000..cc7cb27
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncrypt.java
@@ -0,0 +1,73 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.HybridEncrypt;
+import com.google.crypto.tink.aead.subtle.AeadFactory;
+import com.google.crypto.tink.subtle.Hkdf;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.interfaces.RSAPublicKey;
+import javax.crypto.Cipher;
+
+/**
+ * Hybrid encryption with RSA-KEM as defined in Shoup's ISO standard proposal as KEM, and AEAD as
+ * DEM and HKDF as KDF.
+ *
+ * <p>Shoup's ISO standard proposal is available at https://www.shoup.net/iso/std6.pdf.
+ */
+public final class RsaKemHybridEncrypt implements HybridEncrypt {
+ private final RSAPublicKey recipientPublicKey;
+ private final String hkdfHmacAlgo;
+ private final byte[] hkdfSalt;
+ private final AeadFactory aeadFactory;
+
+ public RsaKemHybridEncrypt(
+ final RSAPublicKey recipientPublicKey,
+ String hkdfHmacAlgo,
+ final byte[] hkdfSalt,
+ AeadFactory aeadFactory)
+ throws GeneralSecurityException {
+ RsaKem.validateRsaModulus(recipientPublicKey.getModulus());
+ this.recipientPublicKey = recipientPublicKey;
+ this.hkdfHmacAlgo = hkdfHmacAlgo;
+ this.hkdfSalt = hkdfSalt;
+ this.aeadFactory = aeadFactory;
+ }
+
+ @Override
+ public byte[] encrypt(final byte[] plaintext, final byte[] contextInfo)
+ throws GeneralSecurityException {
+ // KEM: generate a random shared secret whose bit length is equal to the modulus'.
+ BigInteger mod = recipientPublicKey.getModulus();
+ byte[] sharedSecret = RsaKem.generateSecret(mod);
+
+ // KEM: encrypt the shared secret using the public key.
+ Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding");
+ rsaCipher.init(Cipher.ENCRYPT_MODE, recipientPublicKey);
+ byte[] token = rsaCipher.doFinal(sharedSecret);
+
+ // KDF: derive a DEM key from the shared secret, salt, and contextInfo.
+ byte[] demKey =
+ Hkdf.computeHkdf(
+ hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes());
+
+ Aead aead = aeadFactory.createAead(demKey);
+ byte[] ciphertext = aead.encrypt(plaintext, RsaKem.EMPTY_AAD);
+ return ByteBuffer.allocate(token.length + ciphertext.length).put(token).put(ciphertext).array();
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeysetManager.java b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeysetManager.java
index 8e0da7c..4227d78 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeysetManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeysetManager.java
@@ -27,12 +27,14 @@
import com.google.crypto.tink.KeysetReader;
import com.google.crypto.tink.KeysetWriter;
import com.google.crypto.tink.proto.OutputPrefixType;
-import com.google.crypto.tink.subtle.Hex;
-import com.google.crypto.tink.subtle.Random;
import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.FileNotFoundException;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.ProviderException;
import javax.annotation.concurrent.GuardedBy;
/**
@@ -46,11 +48,9 @@
* <h3>Usage</h3>
*
* <pre>{@code
- * String masterKeyUri = "android-keystore://my_master_key_id";
* AndroidKeysetManager manager = AndroidKeysetManager.Builder()
* .withSharedPref(getApplicationContext(), "my_keyset_name", "my_pref_file_name")
* .withKeyTemplate(AesGcmHkfStreamingKeyManager.aes128GcmHkdf4KBTemplate())
- * .withMasterKeyUri(masterKeyUri)
* .build();
* StreamingAead streamingAead = manager.getKeysetHandle().getPrimitive(StreamingAead.class);
* }</pre>
@@ -59,27 +59,12 @@
* my_pref_file_name} preferences file. If the preference file name is null, it uses the default
* preferences file.
*
- * <p>If the keyset is not found or invalid, and a valid {@link KeyTemplate} is set with {@link
- * AndroidKeysetManager.Builder#withKeyTemplate}, a fresh keyset is generated and is written to the
- * {@code my_keyset_name} preference of the {@code my_pref_file_name} shared preferences file.
+ * <p>If an invalid keyset is found, an {@link InvalidKeyException} is thrown.
*
- * <p>On Android M or newer and if a master key URI is set with {@link
- * AndroidKeysetManager.Builder#withMasterKeyUri}, the keyset is encrypted with a master key
- * generated and stored in <a
- * href="https://developer.android.com/training/articles/keystore.html">Android Keystore</a>. When
- * Tink cannot decrypt the keyset it would assume that it is not encrypted.
- *
- * <p>The master key URI must start with {@code android-keystore://}. If the master key doesn't
- * exist, a fresh one is generated.
- *
- * <p>Usage of Android Keystore can be disabled with {@link
- * AndroidKeysetManager.Builder#doNotUseKeystore}. Android Keystore on certain devices is broken.
- * Tink runs a self-test to detect such problems and disable Android Keystore accordingly. Users can
- * check whether Android Keystore is in use with {@link #isUsingKeystore}.
- *
- * <p>On Android L or older, or when either Android Keystore is disabled or the master key URI is
- * not set, the keyset will be stored in cleartext in private preferences which, thanks to the
- * security of the Android framework, no other apps can read or write.
+ * <p>If a keyset is not found, and a {@link KeyTemplate} is set with {@link
+ * AndroidKeysetManager.Builder#withKeyTemplate(com.google.crypto.tink.KeyTemplate)}, a fresh keyset
+ * is generated and is written to the {@code my_keyset_name} preference of the {@code
+ * my_pref_file_name} shared preferences file.
*
* <p>The resulting manager supports all operations supported by {@link KeysetManager}. For example
* to rotate the keyset, one can do:
@@ -91,13 +76,41 @@
* <p>All operations that manipulate the keyset would automatically persist the new keyset to
* permanent storage.
*
+ * <h3>Opportunistic keyset encryption with Android Keystore</h3>
+ *
+ * <b>Warning:</b> because Android Keystore is unreliable, we strongly recommend disabling it by not
+ * setting any master key URI.
+ *
+ * <p>If a master key URI is set with {@link AndroidKeysetManager.Builder#withMasterKeyUri}, the
+ * keyset may be encrypted with a key generated and stored in <a
+ * href="https://developer.android.com/training/articles/keystore.html">Android Keystore</a>.
+ *
+ * <p>Android Keystore is only available on Android M or newer. Since it has been found that Android
+ * Keystore is unreliable on certain devices. Tink runs a self-test to detect such problems and
+ * disables Android Keystore accordingly, even if a master key URI is set. Users can check whether
+ * Android Keystore is in use with {@link #isUsingKeystore}.
+ *
+ * <p>When Android Keystore is disabled or otherwise unavailable, keysets will be stored in
+ * cleartext. This is not as bad as it sounds because keysets remain inaccessible to any other apps
+ * running on the same device. Moreover, as of July 2020, most active Android devices support either
+ * full-disk encryption or file-based encryption, which provide strong security protection against
+ * key theft even from attackers with physical access to the device. Android Keystore is only useful
+ * when you want to <a
+ * href="https://developer.android.com/training/articles/keystore#UserAuthentication">require user
+ * authentication for key use</a>, which should be done if and only if you're absolutely sure that
+ * Android Keystore is working properly on your target devices.
+ *
+ * <p>The master key URI must start with {@code android-keystore://}. The remaining of the URI is
+ * used as a key ID when calling Android Keystore. If the master key doesn't exist, a fresh one is
+ * generated. If the master key already exists but is unusable, a {@link KeyStoreException} is
+ * thrown.
+ *
* @since 1.0.0
*/
public final class AndroidKeysetManager {
private static final String TAG = AndroidKeysetManager.class.getSimpleName();
private final KeysetReader reader;
private final KeysetWriter writer;
- private final boolean useKeystore;
private final Aead masterKey;
private final KeyTemplate keyTemplate;
@@ -106,29 +119,8 @@
private AndroidKeysetManager(Builder builder) throws GeneralSecurityException, IOException {
reader = builder.reader;
- if (reader == null) {
- throw new IllegalArgumentException(
- "need to specify where to read the keyset from with Builder#withSharedPref");
- }
-
writer = builder.writer;
- if (writer == null) {
- throw new IllegalArgumentException(
- "need to specify where to write the keyset to with Builder#withSharedPref");
- }
-
- if (builder.useKeystore && builder.masterKeyUri == null) {
- throw new IllegalArgumentException(
- "need a master key URI, please set it with Builder#masterKeyUri");
- }
- useKeystore = builder.useKeystore && verifyAndroidKeystore();
-
- if (shouldUseKeystore()) {
- masterKey = AndroidKeystoreKmsClient.getOrGenerateNewAeadKey(builder.masterKeyUri);
- } else {
- masterKey = null;
- }
-
+ masterKey = builder.masterKey;
keyTemplate = builder.keyTemplate;
keysetManager = readOrGenerateNewKeyset();
}
@@ -138,8 +130,10 @@
private KeysetReader reader = null;
private KeysetWriter writer = null;
private String masterKeyUri = null;
+ private Aead masterKey = null;
private boolean useKeystore = true;
private KeyTemplate keyTemplate = null;
+ private KeyStore keyStore = null;
public Builder() {}
@@ -168,7 +162,11 @@
throw new IllegalArgumentException(
"key URI must start with " + AndroidKeystoreKmsClient.PREFIX);
}
- masterKeyUri = val;
+ if (!useKeystore) {
+ throw new IllegalArgumentException(
+ "cannot call withMasterKeyUri() after calling doNotUseKeystore()");
+ }
+ this.masterKeyUri = val;
return this;
}
@@ -197,14 +195,33 @@
*
* <p><b>Warning:</b> When Android Keystore is disabled, keys are stored in cleartext. This
* should be safe because they are stored in private preferences.
+ *
+ * @deprecated Android Keystore can be disabled by not setting a master key URI.
*/
+ @Deprecated
public Builder doNotUseKeystore() {
+ masterKeyUri = null;
useKeystore = false;
return this;
}
- /** @return a {@link KeysetHandle} with the specified options. */
+ /** This is for testing only */
+ Builder withKeyStore(KeyStore val) {
+ this.keyStore = val;
+ return this;
+ }
+
+ /**
+ * Builds and returns a new {@link AndroidKeysetManager} with the specified options.
+ *
+ * @throws IOException If a keyset is found but unusable.
+ * @throws KeystoreException If a master key is found but unusable.
+ * @throws GeneralSecurityException If cannot read an existing keyset or generate a new one.
+ */
public AndroidKeysetManager build() throws GeneralSecurityException, IOException {
+ if (masterKeyUri != null) {
+ masterKey = readOrGenerateNewMasterKey(masterKeyUri, keyStore);
+ }
return new AndroidKeysetManager(this);
}
}
@@ -329,7 +346,7 @@
return this;
}
- /** Returns whether this keyset manager is wrapping keys with Android Keystore. */
+ /** Returns whether Android Keystore is being used to wrap Tink keysets. */
public synchronized boolean isUsingKeystore() {
return shouldUseKeystore();
}
@@ -337,9 +354,9 @@
private KeysetManager readOrGenerateNewKeyset() throws GeneralSecurityException, IOException {
try {
return read();
- } catch (IOException e) {
+ } catch (FileNotFoundException ex) {
// Not found, handle below.
- Log.i(TAG, "cannot read keyset: " + e);
+ Log.w(TAG, "keyset not found, will generate a new one", ex);
}
// Not found.
@@ -350,15 +367,16 @@
write(manager);
return manager;
}
- throw new GeneralSecurityException("cannot obtain keyset handle");
+ throw new GeneralSecurityException("cannot read or generate keyset");
}
private KeysetManager read() throws GeneralSecurityException, IOException {
if (shouldUseKeystore()) {
try {
return KeysetManager.withKeysetHandle(KeysetHandle.read(reader, masterKey));
- } catch (InvalidProtocolBufferException | GeneralSecurityException e) {
- // This edge case happens when
+ } catch (InvalidProtocolBufferException | GeneralSecurityException ex) {
+ // Swallow the exception and attempt to read the keyset in cleartext.
+ // This edge case may happen when either
// - the keyset was generated on a pre M phone which is then upgraded to M or newer, or
// - the keyset was generated with Keystore being disabled, then Keystore is enabled.
// By ignoring the security failure here, an adversary with write access to private
@@ -367,16 +385,11 @@
// overwrite the encrypted keyset in private preferences of an app, said adversaries must
// have the same privilege as the app, thus they can call Android Keystore to read or write
// the encrypted keyset in the first place.
- // So it's okay to ignore the failure and try to read the keyset in cleartext.
- Log.i(TAG, "cannot decrypt keyset: " + e);
+ Log.w(TAG, "cannot decrypt keyset: ", ex);
}
}
- KeysetHandle handle = CleartextKeysetHandle.read(reader);
- if (shouldUseKeystore()) {
- // Opportunistically encrypt the keyset to avoid further fallback to cleartext.
- handle.write(writer, masterKey);
- }
- return KeysetManager.withKeysetHandle(handle);
+
+ return KeysetManager.withKeysetHandle(CleartextKeysetHandle.read(reader));
}
private void write(KeysetManager manager) throws GeneralSecurityException {
@@ -392,7 +405,7 @@
}
private boolean shouldUseKeystore() {
- return useKeystore && isAtLeastM();
+ return masterKey != null && isAtLeastM();
}
private static KeyTemplate.OutputPrefixType fromProto(OutputPrefixType outputPrefixType) {
@@ -414,70 +427,46 @@
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
- /**
- * Does a self-test to verify whether we can rely on Android Keystore, which is broken in many
- * devices.
- */
- private static boolean verifyAndroidKeystore() {
+ private static Aead readOrGenerateNewMasterKey(String keyId, KeyStore keyStore)
+ throws GeneralSecurityException {
if (!isAtLeastM()) {
- return false;
+ Log.w(TAG, "Android Keystore requires at least Android M");
+ return null;
+ }
+
+ AndroidKeystoreKmsClient client;
+ if (keyStore != null) {
+ client = new AndroidKeystoreKmsClient.Builder().setKeyStore(keyStore).build();
+ } else {
+ client = new AndroidKeystoreKmsClient();
+ }
+
+ boolean existed = client.hasKey(keyId);
+ if (!existed) {
+ try {
+ AndroidKeystoreKmsClient.generateNewAeadKey(keyId);
+ } catch (GeneralSecurityException ex) {
+ Log.w(TAG, "cannot use Android Keystore, it'll be disabled", ex);
+ return null;
+ }
}
try {
- String randomKeyId =
- AndroidKeystoreKmsClient.PREFIX
- + new String(Random.randBytes(16), Charset.forName("UTF-8"));
- Aead aead = AndroidKeystoreKmsClient.getOrGenerateNewAeadKey(randomKeyId);
-
- // Empty message.
- // Empty aad.
- byte[] message = new byte[0];
- byte[] aad = new byte[0];
- byte[] ciphertext = aead.encrypt(message, aad);
- byte[] decrypted = aead.decrypt(ciphertext, aad);
- if (decrypted.length != 0) {
- Log.i(
- TAG,
- "cannot use Android Keystore: encryption/decryption of empty message and empty aad"
- + " returns incorrect results");
- return false;
+ return client.getAead(keyId);
+ } catch (GeneralSecurityException | ProviderException ex) {
+ // Throw the exception if the key exists but is unusable. We can't recover by generating a new
+ // key because there might be existing encrypted data under the unusable key.
+ // Users can provide a master key that is stored in StrongBox, which may throw a
+ // ProviderException if there's any problem with it.
+ if (existed) {
+ throw new KeyStoreException(
+ String.format("the master key %s exists but is unusable", keyId), ex);
}
-
- // Non-empty message.
- // Empty aad.
- message = Random.randBytes(10);
- aad = new byte[0];
- ciphertext = aead.encrypt(message, aad);
- decrypted = aead.decrypt(ciphertext, aad);
- if (!Hex.encode(decrypted).equals(Hex.encode(message))) {
- Log.i(
- TAG,
- "cannot use Android Keystore: encryption/decryption of non-empty message and empty"
- + " aad returns incorrect results");
- return false;
- }
-
- // Non-empty message.
- // Non-empty aad.
- message = Random.randBytes(10);
- aad = Random.randBytes(10);
- ciphertext = aead.encrypt(message, aad);
- decrypted = aead.decrypt(ciphertext, aad);
- if (!Hex.encode(decrypted).equals(Hex.encode(message))) {
- Log.i(
- TAG,
- "cannot use Android Keystore: encryption/decryption of non-empty message and"
- + " non-empty aad returns incorrect results");
- return false;
- }
-
- AndroidKeystoreKmsClient.delete(randomKeyId);
-
- return true;
- } catch (Exception ex) {
- Log.i(TAG, "cannot use Android Keystore: " + ex);
+ // Otherwise swallow the exception if the key doesn't exist yet. We can recover by disabling
+ // Keystore.
+ Log.w(TAG, "cannot use Android Keystore, it'll be disabled", ex);
}
- return false;
+ return null;
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreAesGcm.java b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreAesGcm.java
index 98b1863..d408bb1 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreAesGcm.java
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreAesGcm.java
@@ -16,8 +16,6 @@
package com.google.crypto.tink.integration.android;
-import android.annotation.TargetApi;
-import android.os.Build.VERSION_CODES;
import com.google.crypto.tink.Aead;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -35,7 +33,6 @@
*
* @since 1.0.0
*/
-@TargetApi(VERSION_CODES.M)
public final class AndroidKeystoreAesGcm implements Aead {
// All instances of this class use a 12 byte IV and a 16 byte tag.
private static final int IV_SIZE_IN_BYTES = 12;
@@ -52,6 +49,14 @@
}
}
+ /** This is for testing only */
+ AndroidKeystoreAesGcm(String keyId, KeyStore keyStore) throws GeneralSecurityException {
+ key = (SecretKey) keyStore.getKey(keyId, null /* password */);
+ if (key == null) {
+ throw new InvalidKeyException("Keystore cannot load the key with ID: " + keyId);
+ }
+ }
+
@Override
public byte[] encrypt(final byte[] plaintext, final byte[] aad)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreKmsClient.java b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreKmsClient.java
index a85a22b..31924ba 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreKmsClient.java
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/android/AndroidKeystoreKmsClient.java
@@ -16,17 +16,20 @@
package com.google.crypto.tink.integration.android;
-import android.annotation.TargetApi;
import android.os.Build;
-import android.os.Build.VERSION_CODES;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
+import android.util.Log;
import com.google.crypto.tink.Aead;
import com.google.crypto.tink.KmsClient;
+import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.subtle.Validators;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.Arrays;
+import java.util.Locale;
import javax.crypto.KeyGenerator;
/**
@@ -37,29 +40,72 @@
*
* @since 1.0.0
*/
-@TargetApi(VERSION_CODES.M)
public final class AndroidKeystoreKmsClient implements KmsClient {
+ private static final String TAG = AndroidKeystoreKmsClient.class.getSimpleName();
+
/** The prefix of all keys stored in Android Keystore. */
public static final String PREFIX = "android-keystore://";
- private String keyUri;
+ private final String keyUri;
+ private final KeyStore keyStore;
public AndroidKeystoreKmsClient() throws GeneralSecurityException {
- if (!isAtLeastM()) {
- throw new GeneralSecurityException(
- "needs Android Keystore on Android M or newer");
- }
+ this(new Builder());
}
/**
* Constructs an {@link AndroidKeystoreKmsClient} that is bound to a single key identified by
* {@code uri}.
+ *
+ * @deprecated use {@link AndroidKeystoreKmsClient#Builder}.
*/
+ @Deprecated
public AndroidKeystoreKmsClient(String uri) {
- if (!uri.toLowerCase().startsWith(PREFIX)) {
- throw new IllegalArgumentException("key URI must starts with " + PREFIX);
+ this(new Builder().setKeyUri(uri));
+ }
+
+ private AndroidKeystoreKmsClient(Builder builder) {
+ this.keyUri = builder.keyUri;
+ this.keyStore = builder.keyStore;
+ }
+
+ /** Builder for AndroidKeystoreKmsClient */
+ public static final class Builder {
+ String keyUri = null;
+ KeyStore keyStore = null;
+
+ public Builder() {
+ if (!isAtLeastM()) {
+ throw new IllegalStateException("need Android Keystore on Android M or newer");
+ }
+
+ try {
+ this.keyStore = KeyStore.getInstance("AndroidKeyStore");
+ this.keyStore.load(null /* param */);
+ } catch (GeneralSecurityException | IOException ex) {
+ throw new IllegalStateException(ex);
+ }
}
- this.keyUri = uri;
+
+ public Builder setKeyUri(String val) {
+ if (val == null || !val.toLowerCase(Locale.US).startsWith(PREFIX)) {
+ throw new IllegalArgumentException("val must start with " + PREFIX);
+ }
+ this.keyUri = val;
+ return this;
+ }
+
+ public Builder setKeyStore(KeyStore val) {
+ if (val == null) {
+ throw new IllegalArgumentException("val cannot be null");
+ }
+ this.keyStore = val;
+ return this;
+ }
+
+ public AndroidKeystoreKmsClient build() {
+ return new AndroidKeystoreKmsClient(this);
+ }
}
/**
@@ -72,7 +118,7 @@
if (this.keyUri != null && this.keyUri.equals(uri)) {
return true;
}
- return this.keyUri == null && uri.toLowerCase().startsWith(PREFIX);
+ return this.keyUri == null && uri.toLowerCase(Locale.US).startsWith(PREFIX);
}
/**
@@ -95,10 +141,12 @@
return new AndroidKeystoreKmsClient();
}
- private boolean isAtLeastM() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
- }
-
+ /**
+ * Returns an {@link Aead} backed by a key in Android Keystore specified by {@code uri}.
+ *
+ * <p>Since Android Keystore is somewhat unreliable, a self-test is done against the key. This
+ * will incur a small performance penalty.
+ */
@Override
public Aead getAead(String uri) throws GeneralSecurityException {
if (this.keyUri != null && !this.keyUri.equals(uri)) {
@@ -106,12 +154,22 @@
String.format("this client is bound to %s, cannot load keys bound to %s",
this.keyUri, uri));
}
- try {
- return new AndroidKeystoreAesGcm(
- Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, uri));
- } catch (IOException e) {
- throw new GeneralSecurityException(e);
- }
+ Aead aead =
+ new AndroidKeystoreAesGcm(
+ Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, uri), keyStore);
+ return validateAead(aead);
+ }
+
+ /** Deletes a key in Android Keystore. */
+ public void deleteKey(String keyUri) throws GeneralSecurityException {
+ String keyId = Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, keyUri);
+ keyStore.deleteEntry(keyId);
+ }
+
+ /** Returns whether a key exists in Android Keystore. */
+ boolean hasKey(String keyUri) throws GeneralSecurityException {
+ String keyId = Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, keyUri);
+ return keyStore.containsAlias(keyId);
}
/**
@@ -121,13 +179,12 @@
*/
public static Aead getOrGenerateNewAeadKey(String keyUri)
throws GeneralSecurityException, IOException {
- String keyId = Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, keyUri);
- KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- keyStore.load(null /* param */);
- if (!keyStore.containsAlias(keyId)) {
+ AndroidKeystoreKmsClient client = new AndroidKeystoreKmsClient();
+ if (!client.hasKey(keyUri)) {
+ Log.w(TAG, String.format("key URI %s doesn't exist, generating a new one", keyUri));
generateNewAeadKey(keyUri);
}
- return new AndroidKeystoreKmsClient().getAead(keyUri);
+ return client.getAead(keyUri);
}
/**
@@ -137,6 +194,15 @@
*/
public static void generateNewAeadKey(String keyUri)
throws GeneralSecurityException {
+ AndroidKeystoreKmsClient client = new AndroidKeystoreKmsClient();
+ if (client.hasKey(keyUri)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "cannot generate a new key %s because it already exists; please delete it with"
+ + " deleteKey() and try again",
+ keyUri));
+ }
+
String keyId = Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, keyUri);
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
@@ -151,11 +217,23 @@
keyGenerator.generateKey();
}
- /** Deletes a key in Android Keystore. */
- static void delete(String keyUri) throws GeneralSecurityException, IOException {
- String keyId = Validators.validateKmsKeyUriAndRemovePrefix(PREFIX, keyUri);
- KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- keyStore.load(null /* param */);
- keyStore.deleteEntry(keyId);
+ /** Does a self-test to verify whether we can rely on Android Keystore */
+ private static Aead validateAead(Aead aead) throws GeneralSecurityException {
+ // Non-empty message and empty aad.
+ // This is a combination that usually fails.
+ byte[] message = Random.randBytes(10);
+ byte[] aad = new byte[0];
+ byte[] ciphertext = aead.encrypt(message, aad);
+ byte[] decrypted = aead.decrypt(ciphertext, aad);
+ if (!Arrays.equals(message, decrypted)) {
+ throw new KeyStoreException(
+ "cannot use Android Keystore: encryption/decryption of non-empty message and empty"
+ + " aad returns an incorrect result");
+ }
+ return aead;
+ }
+
+ private static boolean isAtLeastM() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/android/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/integration/android/BUILD.bazel
index 4908b31..9b16f4d 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/android/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/android/BUILD.bazel
@@ -1,42 +1,78 @@
load("@build_bazel_rules_android//android:rules.bzl", "android_library")
-load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "*.java",
- ],
- ),
-)
-
-# public interfaces
-
-java_library(
- name = "protos",
- exports = [
- "//proto:tink_java_proto_lite",
+android_library(
+ name = "android_keystore_kms_client",
+ srcs = ["AndroidKeystoreKmsClient.java"],
+ deps = [
+ ":android_keystore_aes_gcm",
+ "//src/main/java/com/google/crypto/tink:core-android",
+ "//src/main/java/com/google/crypto/tink:primitives",
+ "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
],
)
android_library(
- name = "android",
- srcs = [
- ":srcs",
- ],
- javacopts = JAVACOPTS_OSS,
- visibility = ["//visibility:public"],
+ name = "android_keystore_aes_gcm",
+ srcs = ["AndroidKeystoreAesGcm.java"],
deps = [
- ":protos",
- "//src/main/java/com/google/crypto/tink:android",
- "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
+ "//src/main/java/com/google/crypto/tink:primitives",
+ ],
+)
+
+android_library(
+ name = "shared_pref_keyset_writer",
+ srcs = ["SharedPrefKeysetWriter.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:core-android",
"//src/main/java/com/google/crypto/tink/subtle",
- "//src/main/java/com/google/crypto/tink/subtle:aead",
+ ],
+)
+
+android_library(
+ name = "shared_pref_keyset_reader",
+ srcs = ["SharedPrefKeysetReader.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:core-android",
+ "//src/main/java/com/google/crypto/tink/subtle",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "android_keyset_manager",
+ srcs = ["AndroidKeysetManager.java"],
+ deps = [
+ ":android_keystore_kms_client",
+ ":shared_pref_keyset_reader",
+ ":shared_pref_keyset_writer",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle-android",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:keyset_reader-android",
+ "//src/main/java/com/google/crypto/tink:keyset_writer-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_code_findbugs_jsr305",
],
)
+
+# Deprecated, will be removed soon.
+
+android_library(
+ name = "android",
+ exports = [
+ ":android_keyset_manager",
+ ":android_keystore_aes_gcm",
+ ":android_keystore_kms_client",
+ ":shared_pref_keyset_reader",
+ ":shared_pref_keyset_writer",
+ ],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/android/SharedPrefKeysetReader.java b/java_src/src/main/java/com/google/crypto/tink/integration/android/SharedPrefKeysetReader.java
index 8515ff2..93b7425 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/android/SharedPrefKeysetReader.java
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/android/SharedPrefKeysetReader.java
@@ -24,6 +24,8 @@
import com.google.crypto.tink.proto.Keyset;
import com.google.crypto.tink.subtle.Hex;
import com.google.protobuf.ExtensionRegistryLite;
+import java.io.CharConversionException;
+import java.io.FileNotFoundException;
import java.io.IOException;
/**
@@ -60,19 +62,20 @@
}
}
+ @SuppressWarnings("UnusedException")
private byte[] readPref() throws IOException {
try {
String keysetHex = sharedPreferences.getString(keysetName, null /* default value */);
if (keysetHex == null) {
- throw new IOException(
+ throw new FileNotFoundException(
String.format("can't read keyset; the pref value %s does not exist", keysetName));
}
return Hex.decode(keysetHex);
- } catch (ClassCastException | IllegalArgumentException e) {
- throw new IOException(
+ } catch (ClassCastException | IllegalArgumentException ex) {
+ // The original exception is swallowed to prevent leaked key material.
+ throw new CharConversionException(
String.format(
- "can't read keyset; the pref value %s is not a valid hex string", keysetName),
- e);
+ "can't read keyset; the pref value %s is not a valid hex string", keysetName));
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/awskms/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/integration/awskms/BUILD.bazel
index 1f8a2d8..ca8600c 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/awskms/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/awskms/BUILD.bazel
@@ -1,32 +1,28 @@
-load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
-
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "*.java",
- ],
- ),
-)
-
-# public interfaces
+package(default_visibility = ["//visibility:public"])
java_library(
- name = "awskms",
- srcs = [
- ":srcs",
+ name = "aws_kms_aead",
+ srcs = ["AwsKmsAead.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:aead",
+ "@maven//:com_amazonaws_aws_java_sdk_core",
+ "@maven//:com_amazonaws_aws_java_sdk_kms",
],
- javacopts = JAVACOPTS_OSS,
+)
+
+java_library(
+ name = "aws_kms_client",
+ srcs = ["AwsKmsClient.java"],
plugins = [
":auto_service_plugin",
],
deps = [
- "//src/main/java/com/google/crypto/tink",
- "//src/main/java/com/google/crypto/tink/subtle",
+ ":aws_kms_aead",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
"@maven//:com_amazonaws_aws_java_sdk_core",
"@maven//:com_amazonaws_aws_java_sdk_kms",
"@maven//:com_google_auto_service_auto_service_annotations",
@@ -42,3 +38,13 @@
"@maven//:com_google_auto_service_auto_service",
],
)
+
+# Deprecated rules, will be removed soon.
+
+java_library(
+ name = "awskms",
+ exports = [
+ ":aws_kms_aead",
+ ":aws_kms_client",
+ ],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/integration/gcpkms/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/integration/gcpkms/BUILD.bazel
index 7c00c2b..a5628d1 100644
--- a/java_src/src/main/java/com/google/crypto/tink/integration/gcpkms/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/integration/gcpkms/BUILD.bazel
@@ -1,32 +1,19 @@
-load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
-
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "*.java",
- ],
- ),
-)
-
-# public interfaces
+package(default_visibility = ["//visibility:public"])
java_library(
- name = "gcpkms",
- srcs = [
- ":srcs",
- ],
- javacopts = JAVACOPTS_OSS,
+ name = "gcp_kms_client",
+ srcs = ["GcpKmsClient.java"],
plugins = [
":auto_service_plugin",
],
deps = [
- "//src/main/java/com/google/crypto/tink",
- "//src/main/java/com/google/crypto/tink/subtle",
+ ":gcp_kms_aead",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:core",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
"@maven//:com_google_api_client_google_api_client",
"@maven//:com_google_apis_google_api_services_cloudkms",
"@maven//:com_google_auto_service_auto_service_annotations",
@@ -36,6 +23,15 @@
],
)
+java_library(
+ name = "gcp_kms_aead",
+ srcs = ["GcpKmsAead.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:aead",
+ "@maven//:com_google_apis_google_api_services_cloudkms",
+ ],
+)
+
java_plugin(
name = "auto_service_plugin",
processor_class = "com.google.auto.service.processor.AutoServiceProcessor",
@@ -44,3 +40,14 @@
"@maven//:com_google_auto_service_auto_service",
],
)
+
+# Deprecated rules, will be removed soon.
+
+java_library(
+ name = "gcpkms",
+ tags = ["avoid_dep"],
+ exports = [
+ ":gcp_kms_aead",
+ ":gcp_kms_client",
+ ],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/jose/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/jose/BUILD.bazel
new file mode 100644
index 0000000..f396045
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/jose/BUILD.bazel
@@ -0,0 +1,17 @@
+licenses(["notice"])
+
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "jws_mac",
+ srcs = ["JwsMac.java"],
+ deps = [
+ ":jwt",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+java_library(
+ name = "jwt",
+ srcs = ["Jwt.java"],
+)
diff --git a/java_src/src/main/java/com/google/crypto/tink/jose/JwsMac.java b/java_src/src/main/java/com/google/crypto/tink/jose/JwsMac.java
new file mode 100644
index 0000000..840d044
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/jose/JwsMac.java
@@ -0,0 +1,33 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.jose;
+
+import com.google.errorprone.annotations.Immutable;
+import java.security.GeneralSecurityException;
+
+/**
+ * Interface for JSON Web Signature (JWS) Message Authentication Code (MAC), as described in RFC
+ * 7515.
+ *
+ * <h3>Security guarantees: similar to {@link com.google.crypto.tink.Mac}.</h3>
+ */
+@Immutable
+public interface JwsMac {
+ /** Computes a MAC and encodes a JWT in JWS compact serialization format. */
+ String computeMacThenEncode(Jwt payload) throws GeneralSecurityException;
+
+ /** Verifies a MAC and decodes a JWT in JWS compact serialization format. */
+ Jwt verifyMacThenDecode(String compact) throws GeneralSecurityException;
+}
diff --git a/javascript/keyset_writer.js b/java_src/src/main/java/com/google/crypto/tink/jose/Jwt.java
similarity index 60%
copy from javascript/keyset_writer.js
copy to java_src/src/main/java/com/google/crypto/tink/jose/Jwt.java
index cc715df..5237e5a 100644
--- a/javascript/keyset_writer.js
+++ b/java_src/src/main/java/com/google/crypto/tink/jose/Jwt.java
@@ -12,22 +12,9 @@
//
////////////////////////////////////////////////////////////////////////////////
-goog.module('tink.KeysetWriter');
+package com.google.crypto.tink.jose;
-const {PbEncryptedKeyset, PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
-
-/**
- * KeysetWriter knows how to write a keyset or an encrypted keyset to some
- * storage system.
- *
- * @record
- */
-class KeysetWriter {
- /**
- * @param {!PbKeyset|!PbEncryptedKeyset} keyset
- * @return {!Uint8Array}
- */
- write(keyset) {}
+/** A JWT is a string representing a set of claims as a JSON object, as described in RFC 7519. */
+public final class Jwt {
+ private Jwt() {}
}
-
-exports = KeysetWriter;
diff --git a/apps/jose/README.md b/java_src/src/main/java/com/google/crypto/tink/jose/README.md
similarity index 100%
rename from apps/jose/README.md
rename to java_src/src/main/java/com/google/crypto/tink/jose/README.md
diff --git a/java_src/src/main/java/com/google/crypto/tink/mac/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/mac/BUILD.bazel
index 199e597..719c12b 100644
--- a/java_src/src/main/java/com/google/crypto/tink/mac/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/mac/BUILD.bazel
@@ -1,8 +1,183 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "hmac_key_manager",
+ srcs = ["HmacKeyManager.java"],
+ deps = [
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_hmac_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_mac",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "hmac_key_manager-android",
+ srcs = ["HmacKeyManager.java"],
+ deps = [
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_hmac_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_mac",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "mac_factory",
+ srcs = ["MacFactory.java"],
+ deps = [
+ ":mac_wrapper",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+android_library(
+ name = "mac_factory-android",
+ srcs = ["MacFactory.java"],
+ deps = [
+ ":mac_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+java_library(
+ name = "mac_key_templates",
+ srcs = ["MacKeyTemplates.java"],
+ deps = [
+ ":aes_cmac_key_manager",
+ ":hmac_key_manager",
+ "//proto:aes_cmac_java_proto",
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ ],
+)
+
+android_library(
+ name = "mac_key_templates-android",
+ srcs = ["MacKeyTemplates.java"],
+ deps = [
+ ":aes_cmac_key_manager-android",
+ ":hmac_key_manager-android",
+ "//proto:aes_cmac_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "mac_wrapper",
+ srcs = ["MacWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "mac_wrapper-android",
+ srcs = ["MacWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "mac_config",
+ srcs = ["MacConfig.java"],
+ deps = [
+ ":aes_cmac_key_manager",
+ ":hmac_key_manager",
+ ":mac_wrapper",
+ "//proto:config_java_proto",
+ ],
+)
+
+android_library(
+ name = "mac_config-android",
+ srcs = ["MacConfig.java"],
+ deps = [
+ ":aes_cmac_key_manager-android",
+ ":hmac_key_manager-android",
+ ":mac_wrapper-android",
+ "//proto:config_java_proto_lite",
+ ],
+)
+
+java_library(
+ name = "aes_cmac_key_manager",
+ srcs = ["AesCmacKeyManager.java"],
+ deps = [
+ "//proto:aes_cmac_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_cmac",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aes_cmac_key_manager-android",
+ srcs = ["AesCmacKeyManager.java"],
+ deps = [
+ "//proto:aes_cmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_cmac",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+# Deprecated rules, will be removed soon
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/mac/HmacKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/mac/HmacKeyManager.java
index 703fc11..11e0691 100644
--- a/java_src/src/main/java/com/google/crypto/tink/mac/HmacKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/mac/HmacKeyManager.java
@@ -25,7 +25,8 @@
import com.google.crypto.tink.proto.HmacKeyFormat;
import com.google.crypto.tink.proto.HmacParams;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
-import com.google.crypto.tink.subtle.MacJce;
+import com.google.crypto.tink.subtle.PrfHmacJce;
+import com.google.crypto.tink.subtle.PrfMac;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.subtle.Validators;
import com.google.protobuf.ByteString;
@@ -37,7 +38,8 @@
import javax.crypto.spec.SecretKeySpec;
/**
- * This key manager generates new {@code HmacKey} keys and produces new instances of {@code MacJce}.
+ * This key manager generates new {@code HmacKey} keys and produces new instances of {@code
+ * PrfHmacJce}.
*/
public final class HmacKeyManager extends KeyTypeManager<HmacKey> {
public HmacKeyManager() {
@@ -52,11 +54,11 @@
int tagSize = key.getParams().getTagSize();
switch (hash) {
case SHA1:
- return new MacJce("HMACSHA1", keySpec, tagSize);
+ return new PrfMac(new PrfHmacJce("HMACSHA1", keySpec), tagSize);
case SHA256:
- return new MacJce("HMACSHA256", keySpec, tagSize);
+ return new PrfMac(new PrfHmacJce("HMACSHA256", keySpec), tagSize);
case SHA512:
- return new MacJce("HMACSHA512", keySpec, tagSize);
+ return new PrfMac(new PrfHmacJce("HMACSHA512", keySpec), tagSize);
default:
throw new GeneralSecurityException("unknown hash");
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/mac/MacConfig.java b/java_src/src/main/java/com/google/crypto/tink/mac/MacConfig.java
index 802a70a..7c202c2 100644
--- a/java_src/src/main/java/com/google/crypto/tink/mac/MacConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/mac/MacConfig.java
@@ -16,13 +16,13 @@
package com.google.crypto.tink.mac;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.Mac} key types supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.Mac} key types supported in a particular release of
+ * Tink.
*
* <p>To register all Mac key types provided in the latest Tink version one can do:
*
@@ -30,30 +30,28 @@
* MacConfig.register();
* }</pre>
*
- * <p>For more information on how to obtain and use instances of Mac, see {@link MacFactory}.
+ * <p>For more information on how to obtain and use instances of Mac, see {@link
+ * com.google.crypto.tink.KeysetHandle#getPrimitive}.
*
* @since 1.0.0
*/
public final class MacConfig {
public static final String HMAC_TYPE_URL = new HmacKeyManager().getKeyType();
- /** @deprecated */
- @Deprecated
- public static final RegistryConfig TINK_1_0_0 = RegistryConfig.getDefaultInstance();
+ /** @deprecated use {@link #register} */
+ @Deprecated public static final RegistryConfig TINK_1_0_0 = RegistryConfig.getDefaultInstance();
/**
- * @deprecated
+ * @deprecated use {@link #register}
* @since 1.1.0
*/
- @Deprecated
- public static final RegistryConfig TINK_1_1_0 = TINK_1_0_0;
+ @Deprecated public static final RegistryConfig TINK_1_1_0 = TINK_1_0_0;
/**
- * @deprecated
+ * @deprecated use {@link #register}
* @since 1.2.0
*/
- @Deprecated
- public static final RegistryConfig LATEST = TINK_1_0_0;
+ @Deprecated public static final RegistryConfig LATEST = TINK_1_0_0;
static {
try {
@@ -64,7 +62,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} and {@link com.google.crypto.tink.KeyManager} needed to
* handle Mac key types supported in Tink.
*
@@ -76,7 +74,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} and {@link com.google.crypto.tink.KeyManager} needed to
* handle Mac key types supported in Tink.
*
@@ -89,7 +87,8 @@
}
/**
- * Registers with the {@code Registry} all Mac key types released with the latest version of Tink.
+ * Registers with the {@code com.google.crypto.tink.Registry} all Mac key types released with the
+ * latest version of Tink.
*
* <p>Deprecated-yet-still-supported key types are registered in so-called "no new key"-mode,
* which allows for usage of existing keys forbids generation of new key material.
@@ -100,4 +99,6 @@
public static void registerStandardKeyTypes() throws GeneralSecurityException {
register();
}
+
+ private MacConfig() {}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/mac/MacKeyTemplates.java b/java_src/src/main/java/com/google/crypto/tink/mac/MacKeyTemplates.java
index 9c86781..8247160 100644
--- a/java_src/src/main/java/com/google/crypto/tink/mac/MacKeyTemplates.java
+++ b/java_src/src/main/java/com/google/crypto/tink/mac/MacKeyTemplates.java
@@ -139,4 +139,6 @@
.setOutputPrefixType(OutputPrefixType.TINK)
.build();
}
+
+ private MacKeyTemplates() {}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/mac/MacWrapper.java b/java_src/src/main/java/com/google/crypto/tink/mac/MacWrapper.java
index 1d0f68b..0e01395 100644
--- a/java_src/src/main/java/com/google/crypto/tink/mac/MacWrapper.java
+++ b/java_src/src/main/java/com/google/crypto/tink/mac/MacWrapper.java
@@ -67,7 +67,7 @@
// clearly insecure, thus should be discouraged.
throw new GeneralSecurityException("tag too short");
}
- byte[] prefix = Arrays.copyOfRange(mac, 0, CryptoFormat.NON_RAW_PREFIX_SIZE);
+ byte[] prefix = Arrays.copyOf(mac, CryptoFormat.NON_RAW_PREFIX_SIZE);
byte[] macNoPrefix = Arrays.copyOfRange(mac, CryptoFormat.NON_RAW_PREFIX_SIZE, mac.length);
List<PrimitiveSet.Entry<Mac>> entries = primitives.getPrimitive(prefix);
for (PrimitiveSet.Entry<Mac> entry : entries) {
@@ -80,7 +80,7 @@
// If there is no exception, the MAC is valid and we can return.
return;
} catch (GeneralSecurityException e) {
- logger.info("tag prefix matches a key, but cannot verify: " + e.toString());
+ logger.info("tag prefix matches a key, but cannot verify: " + e);
// Ignored as we want to continue verification with the remaining keys.
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/prf/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/prf/BUILD.bazel
index 9b63da2..a626133 100644
--- a/java_src/src/main/java/com/google/crypto/tink/prf/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/prf/BUILD.bazel
@@ -2,7 +2,7 @@
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
java_library(
name = "hkdf_prf_key_manager",
@@ -13,8 +13,12 @@
"//proto:common_java_proto",
"//proto:hkdf_prf_java_proto",
"//proto:tink_java_proto",
- "//src/main/java/com/google/crypto/tink:core",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
"//src/main/java/com/google/crypto/tink/subtle/prf:hkdf_streaming_prf",
"//src/main/java/com/google/crypto/tink/subtle/prf:prf_impl",
"//src/main/java/com/google/crypto/tink/subtle/prf:streaming_prf",
@@ -68,7 +72,9 @@
deps = [
":prf_set",
"//proto:tink_java_proto",
- "//src/main/java/com/google/crypto/tink:core",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
@@ -82,8 +88,12 @@
"//proto:common_java_proto_lite",
"//proto:hkdf_prf_java_proto_lite",
"//proto:tink_java_proto_lite",
- "//src/main/java/com/google/crypto/tink:core-android",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
"//src/main/java/com/google/crypto/tink/subtle/prf:hkdf_streaming_prf",
"//src/main/java/com/google/crypto/tink/subtle/prf:prf_impl",
"//src/main/java/com/google/crypto/tink/subtle/prf:streaming_prf",
@@ -120,7 +130,9 @@
deps = [
":prf_set",
"//proto:tink_java_proto_lite",
- "//src/main/java/com/google/crypto/tink:core-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/signature/BUILD.bazel
index 0449ec4..05c684f 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/BUILD.bazel
@@ -1,8 +1,575 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "signature_config",
+ srcs = ["SignatureConfig.java"],
+ deps = [
+ ":ecdsa_sign_key_manager",
+ ":ecdsa_verify_key_manager",
+ ":ed25519_private_key_manager",
+ ":ed25519_public_key_manager",
+ ":public_key_sign_wrapper",
+ ":public_key_verify_wrapper",
+ ":rsa_ssa_pkcs1_sign_key_manager",
+ ":rsa_ssa_pkcs1_verify_key_manager",
+ ":rsa_ssa_pss_sign_key_manager",
+ "//proto:config_java_proto",
+ ],
+)
+
+java_library(
+ name = "sig_util",
+ srcs = ["SigUtil.java"],
+ deps = [
+ "//proto:common_java_proto",
+ "//proto:ecdsa_java_proto",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
+ ],
+)
+
+java_library(
+ name = "ecdsa_verify_key_manager",
+ srcs = ["EcdsaVerifyKeyManager.java"],
+ deps = [
+ ":sig_util",
+ "//proto:ecdsa_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "signature_pem_keyset_reader",
+ srcs = ["SignaturePemKeysetReader.java"],
+ deps = [
+ ":ecdsa_verify_key_manager",
+ ":rsa_ssa_pkcs1_verify_key_manager",
+ ":rsa_ssa_pss_verify_key_manager",
+ "//proto:common_java_proto",
+ "//proto:ecdsa_java_proto",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:keyset_reader",
+ "//src/main/java/com/google/crypto/tink/subtle:pem_key_type",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pss_verify_key_manager",
+ srcs = ["RsaSsaPssVerifyKeyManager.java"],
+ deps = [
+ ":sig_util",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "ecdsa_sign_key_manager",
+ srcs = ["EcdsaSignKeyManager.java"],
+ deps = [
+ ":ecdsa_verify_key_manager",
+ ":sig_util",
+ "//proto:common_java_proto",
+ "//proto:ecdsa_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "public_key_sign_wrapper",
+ srcs = ["PublicKeySignWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "public_key_verify_config",
+ srcs = ["PublicKeyVerifyConfig.java"],
+ deps = [
+ ":signature_config",
+ "//src/main/java/com/google/crypto/tink:config",
+ ],
+)
+
+java_library(
+ name = "signature_key_templates",
+ srcs = ["SignatureKeyTemplates.java"],
+ deps = [
+ ":ecdsa_sign_key_manager",
+ ":ed25519_private_key_manager",
+ ":rsa_ssa_pkcs1_sign_key_manager",
+ ":rsa_ssa_pss_sign_key_manager",
+ "//proto:common_java_proto",
+ "//proto:ecdsa_java_proto",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//proto:tink_java_proto",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pkcs1_sign_key_manager",
+ srcs = ["RsaSsaPkcs1SignKeyManager.java"],
+ deps = [
+ ":rsa_ssa_pkcs1_verify_key_manager",
+ ":sig_util",
+ "//proto:common_java_proto",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "public_key_sign_factory",
+ srcs = ["PublicKeySignFactory.java"],
+ deps = [
+ ":public_key_sign_wrapper",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "public_key_sign_config",
+ srcs = ["PublicKeySignConfig.java"],
+ deps = [
+ ":signature_config",
+ "//src/main/java/com/google/crypto/tink:config",
+ ],
+)
+
+java_library(
+ name = "public_key_verify_wrapper",
+ srcs = ["PublicKeyVerifyWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pss_sign_key_manager",
+ srcs = ["RsaSsaPssSignKeyManager.java"],
+ deps = [
+ ":rsa_ssa_pss_verify_key_manager",
+ ":sig_util",
+ "//proto:common_java_proto",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "ed25519_private_key_manager",
+ srcs = ["Ed25519PrivateKeyManager.java"],
+ deps = [
+ ":ed25519_public_key_manager",
+ "//proto:ed25519_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_sign",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pkcs1_verify_key_manager",
+ srcs = ["RsaSsaPkcs1VerifyKeyManager.java"],
+ deps = [
+ ":sig_util",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "public_key_verify_factory",
+ srcs = ["PublicKeyVerifyFactory.java"],
+ deps = [
+ ":public_key_verify_wrapper",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ ],
+)
+
+java_library(
+ name = "ed25519_public_key_manager",
+ srcs = ["Ed25519PublicKeyManager.java"],
+ deps = [
+ "//proto:ed25519_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+# Android packages
+
+android_library(
+ name = "signature_config-android",
+ srcs = ["SignatureConfig.java"],
+ deps = [
+ ":ecdsa_sign_key_manager-android",
+ ":ecdsa_verify_key_manager-android",
+ ":ed25519_private_key_manager-android",
+ ":ed25519_public_key_manager-android",
+ ":public_key_sign_wrapper-android",
+ ":public_key_verify_wrapper-android",
+ ":rsa_ssa_pkcs1_sign_key_manager-android",
+ ":rsa_ssa_pkcs1_verify_key_manager-android",
+ ":rsa_ssa_pss_sign_key_manager-android",
+ "//proto:config_java_proto_lite",
+ ],
+)
+
+android_library(
+ name = "sig_util-android",
+ srcs = ["SigUtil.java"],
+ deps = [
+ "//proto:common_java_proto_lite",
+ "//proto:ecdsa_java_proto_lite",
+ "//proto:rsa_ssa_pkcs1_java_proto_lite",
+ "//proto:rsa_ssa_pss_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
+ ],
+)
+
+android_library(
+ name = "ecdsa_verify_key_manager-android",
+ srcs = ["EcdsaVerifyKeyManager.java"],
+ deps = [
+ ":sig_util-android",
+ "//proto:ecdsa_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "signature_pem_keyset_reader-android",
+ srcs = ["SignaturePemKeysetReader.java"],
+ deps = [
+ ":ecdsa_verify_key_manager-android",
+ ":rsa_ssa_pkcs1_verify_key_manager-android",
+ ":rsa_ssa_pss_verify_key_manager-android",
+ "//proto:common_java_proto_lite",
+ "//proto:ecdsa_java_proto_lite",
+ "//proto:rsa_ssa_pkcs1_java_proto_lite",
+ "//proto:rsa_ssa_pss_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:keyset_reader-android",
+ "//src/main/java/com/google/crypto/tink/subtle:pem_key_type",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "rsa_ssa_pss_verify_key_manager-android",
+ srcs = ["RsaSsaPssVerifyKeyManager.java"],
+ deps = [
+ ":sig_util-android",
+ "//proto:rsa_ssa_pss_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "ecdsa_sign_key_manager-android",
+ srcs = ["EcdsaSignKeyManager.java"],
+ deps = [
+ ":ecdsa_verify_key_manager-android",
+ ":sig_util-android",
+ "//proto:common_java_proto_lite",
+ "//proto:ecdsa_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "public_key_sign_wrapper-android",
+ srcs = ["PublicKeySignWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "public_key_verify_config-android",
+ srcs = ["PublicKeyVerifyConfig.java"],
+ deps = [
+ ":signature_config-android",
+ "//src/main/java/com/google/crypto/tink:config-android",
+ ],
+)
+
+android_library(
+ name = "signature_key_templates-android",
+ srcs = ["SignatureKeyTemplates.java"],
+ deps = [
+ ":ecdsa_sign_key_manager-android",
+ ":ed25519_private_key_manager-android",
+ ":rsa_ssa_pkcs1_sign_key_manager-android",
+ ":rsa_ssa_pss_sign_key_manager-android",
+ "//proto:common_java_proto_lite",
+ "//proto:ecdsa_java_proto_lite",
+ "//proto:rsa_ssa_pkcs1_java_proto_lite",
+ "//proto:rsa_ssa_pss_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "rsa_ssa_pkcs1_sign_key_manager-android",
+ srcs = ["RsaSsaPkcs1SignKeyManager.java"],
+ deps = [
+ ":rsa_ssa_pkcs1_verify_key_manager-android",
+ ":sig_util-android",
+ "//proto:common_java_proto_lite",
+ "//proto:rsa_ssa_pkcs1_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "public_key_sign_factory-android",
+ srcs = ["PublicKeySignFactory.java"],
+ deps = [
+ ":public_key_sign_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "public_key_sign_config-android",
+ srcs = ["PublicKeySignConfig.java"],
+ deps = [
+ ":signature_config-android",
+ "//src/main/java/com/google/crypto/tink:config-android",
+ ],
+)
+
+android_library(
+ name = "public_key_verify_wrapper-android",
+ srcs = ["PublicKeyVerifyWrapper.java"],
+ deps = [
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:crypto_format-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ ],
+)
+
+android_library(
+ name = "rsa_ssa_pss_sign_key_manager-android",
+ srcs = ["RsaSsaPssSignKeyManager.java"],
+ deps = [
+ ":rsa_ssa_pss_verify_key_manager-android",
+ ":sig_util-android",
+ "//proto:common_java_proto_lite",
+ "//proto:rsa_ssa_pss_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "ed25519_private_key_manager-android",
+ srcs = ["Ed25519PrivateKeyManager.java"],
+ deps = [
+ ":ed25519_public_key_manager-android",
+ "//proto:ed25519_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_sign",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "rsa_ssa_pkcs1_verify_key_manager-android",
+ srcs = ["RsaSsaPkcs1VerifyKeyManager.java"],
+ deps = [
+ ":sig_util-android",
+ "//proto:rsa_ssa_pkcs1_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "public_key_verify_factory-android",
+ srcs = ["PublicKeyVerifyFactory.java"],
+ deps = [
+ ":public_key_verify_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ ],
+)
+
+android_library(
+ name = "ed25519_public_key_manager-android",
+ srcs = ["Ed25519PublicKeyManager.java"],
+ deps = [
+ "//proto:ed25519_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+# Deprecated, will be removed soon.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaSignKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaSignKeyManager.java
index c03f3ef..41574b7 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaSignKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaSignKeyManager.java
@@ -17,6 +17,7 @@
package com.google.crypto.tink.signature;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.PrivateKeyTypeManager;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.Registry;
@@ -50,7 +51,7 @@
super(
EcdsaPrivateKey.class,
EcdsaPublicKey.class,
- new PrimitiveFactory<PublicKeySign, EcdsaPrivateKey>(PublicKeySign.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeySign, EcdsaPrivateKey>(PublicKeySign.class) {
@Override
public PublicKeySign getPrimitive(EcdsaPrivateKey key) throws GeneralSecurityException {
ECPrivateKey privateKey =
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaVerifyKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaVerifyKeyManager.java
index d8205b3..c266e34 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaVerifyKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/EcdsaVerifyKeyManager.java
@@ -37,7 +37,8 @@
public EcdsaVerifyKeyManager() {
super(
EcdsaPublicKey.class,
- new PrimitiveFactory<PublicKeyVerify, EcdsaPublicKey>(PublicKeyVerify.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeyVerify, EcdsaPublicKey>(
+ PublicKeyVerify.class) {
@Override
public PublicKeyVerify getPrimitive(EcdsaPublicKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PrivateKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PrivateKeyManager.java
index 34b83f1..cd90ee6 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PrivateKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PrivateKeyManager.java
@@ -17,6 +17,7 @@
package com.google.crypto.tink.signature;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.PrivateKeyTypeManager;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.Registry;
@@ -41,7 +42,7 @@
super(
Ed25519PrivateKey.class,
Ed25519PublicKey.class,
- new PrimitiveFactory<PublicKeySign, Ed25519PrivateKey>(PublicKeySign.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeySign, Ed25519PrivateKey>(PublicKeySign.class) {
@Override
public PublicKeySign getPrimitive(Ed25519PrivateKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PublicKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PublicKeyManager.java
index e0a0775..de74b1d 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PublicKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/Ed25519PublicKeyManager.java
@@ -35,7 +35,8 @@
public Ed25519PublicKeyManager() {
super(
Ed25519PublicKey.class,
- new PrimitiveFactory<PublicKeyVerify, Ed25519PublicKey>(PublicKeyVerify.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeyVerify, Ed25519PublicKey>(
+ PublicKeyVerify.class) {
@Override
public PublicKeyVerify getPrimitive(Ed25519PublicKey keyProto) {
return new Ed25519Verify(keyProto.getKeyValue().toByteArray());
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1SignKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1SignKeyManager.java
index fa97b2b..3afa77a 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1SignKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1SignKeyManager.java
@@ -17,6 +17,7 @@
package com.google.crypto.tink.signature;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.PrivateKeyTypeManager;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.Registry;
@@ -36,7 +37,6 @@
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateCrtKey;
@@ -58,7 +58,8 @@
super(
RsaSsaPkcs1PrivateKey.class,
RsaSsaPkcs1PublicKey.class,
- new PrimitiveFactory<PublicKeySign, RsaSsaPkcs1PrivateKey>(PublicKeySign.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeySign, RsaSsaPkcs1PrivateKey>(
+ PublicKeySign.class) {
@Override
public PublicKeySign getPrimitive(RsaSsaPkcs1PrivateKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1VerifyKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1VerifyKeyManager.java
index 08c1a05..efe1e77 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1VerifyKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPkcs1VerifyKeyManager.java
@@ -39,7 +39,8 @@
public RsaSsaPkcs1VerifyKeyManager() {
super(
RsaSsaPkcs1PublicKey.class,
- new PrimitiveFactory<PublicKeyVerify, RsaSsaPkcs1PublicKey>(PublicKeyVerify.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeyVerify, RsaSsaPkcs1PublicKey>(
+ PublicKeyVerify.class) {
@Override
public PublicKeyVerify getPrimitive(RsaSsaPkcs1PublicKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManager.java
index 6135789..9dc6532 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManager.java
@@ -17,6 +17,7 @@
package com.google.crypto.tink.signature;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.PrivateKeyTypeManager;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.Registry;
@@ -36,7 +37,6 @@
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateCrtKey;
@@ -58,7 +58,8 @@
super(
RsaSsaPssPrivateKey.class,
RsaSsaPssPublicKey.class,
- new PrimitiveFactory<PublicKeySign, RsaSsaPssPrivateKey>(PublicKeySign.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeySign, RsaSsaPssPrivateKey>(
+ PublicKeySign.class) {
@Override
public PublicKeySign getPrimitive(RsaSsaPssPrivateKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssVerifyKeyManager.java b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssVerifyKeyManager.java
index d370178..907f262 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssVerifyKeyManager.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/RsaSsaPssVerifyKeyManager.java
@@ -40,7 +40,8 @@
public RsaSsaPssVerifyKeyManager() {
super(
RsaSsaPssPublicKey.class,
- new PrimitiveFactory<PublicKeyVerify, RsaSsaPssPublicKey>(PublicKeyVerify.class) {
+ new KeyTypeManager.PrimitiveFactory<PublicKeyVerify, RsaSsaPssPublicKey>(
+ PublicKeyVerify.class) {
@Override
public PublicKeyVerify getPrimitive(RsaSsaPssPublicKey keyProto)
throws GeneralSecurityException {
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/SigUtil.java b/java_src/src/main/java/com/google/crypto/tink/signature/SigUtil.java
index 3500417..d42f155 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/SigUtil.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/SigUtil.java
@@ -108,6 +108,9 @@
if (params.getSigHash() != params.getMgf1Hash()) {
throw new GeneralSecurityException("MGF1 hash is different from signature hash");
}
+ if (params.getSaltLength() < 0) {
+ throw new GeneralSecurityException("salt length is negative");
+ }
}
/** Converts protobuf enum {@code HashType} to raw Java enum {@code Enums.HashType}. */
@@ -136,7 +139,7 @@
case NIST_P521:
return EllipticCurves.CurveType.NIST_P521;
default:
- throw new GeneralSecurityException("unknown curve type: " + type);
+ throw new GeneralSecurityException("unknown curve type: " + type.name());
}
}
@@ -152,7 +155,7 @@
case DER:
return EllipticCurves.EcdsaEncoding.DER;
default:
- throw new GeneralSecurityException("unknown ECDSA encoding: " + encoding);
+ throw new GeneralSecurityException("unknown ECDSA encoding: " + encoding.name());
}
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/signature/SignatureConfig.java b/java_src/src/main/java/com/google/crypto/tink/signature/SignatureConfig.java
index 9d6b05c..0f2804a 100644
--- a/java_src/src/main/java/com/google/crypto/tink/signature/SignatureConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/signature/SignatureConfig.java
@@ -16,14 +16,13 @@
package com.google.crypto.tink.signature;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.PublicKeySign} and {@link com.google.crypto.tink.PublicKeyVerify} key
- * types supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.PublicKeySign} and {@link
+ * com.google.crypto.tink.PublicKeyVerify} key types supported in a particular release of Tink.
*
* <p>To register all PublicKeySign and PublicKeyVerify key types provided in the latest Tink
* version one can do:
@@ -71,7 +70,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle PublicKeySign and PublicKeyVerify key types
* supported in Tink.
*
@@ -83,7 +82,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle PublicKeySign and PublicKeyVerify key types
* supported in Tink.
*
diff --git a/java_src/src/main/java/com/google/crypto/tink/streamingaead/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/streamingaead/BUILD.bazel
index ae5e82a..4be763e 100644
--- a/java_src/src/main/java/com/google/crypto/tink/streamingaead/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/streamingaead/BUILD.bazel
@@ -1,8 +1,287 @@
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "streaming_aead_util",
+ srcs = ["StreamingAeadUtil.java"],
+ deps = ["//proto:common_java_proto"],
+)
+
+java_library(
+ name = "streaming_aead_key_templates",
+ srcs = ["StreamingAeadKeyTemplates.java"],
+ deps = [
+ ":aes_ctr_hmac_streaming_key_manager",
+ ":aes_gcm_hkdf_streaming_key_manager",
+ "//proto:aes_ctr_hmac_streaming_java_proto",
+ "//proto:aes_gcm_hkdf_streaming_java_proto",
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ ],
+)
+
+java_library(
+ name = "streaming_aead_config",
+ srcs = ["StreamingAeadConfig.java"],
+ deps = [
+ ":aes_ctr_hmac_streaming_key_manager",
+ ":aes_gcm_hkdf_streaming_key_manager",
+ ":streaming_aead_wrapper",
+ "//proto:config_java_proto",
+ ],
+)
+
+java_library(
+ name = "seekable_byte_channel_decrypter",
+ srcs = ["SeekableByteChannelDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+java_library(
+ name = "input_stream_decrypter",
+ srcs = ["InputStreamDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+java_library(
+ name = "streaming_aead_helper",
+ srcs = ["StreamingAeadHelper.java"],
+ deps = [
+ ":input_stream_decrypter",
+ ":readable_byte_channel_decrypter",
+ ":seekable_byte_channel_decrypter",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+java_library(
+ name = "streaming_aead_factory",
+ srcs = ["StreamingAeadFactory.java"],
+ deps = [
+ ":streaming_aead_wrapper",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+java_library(
+ name = "aes_gcm_hkdf_streaming_key_manager",
+ srcs = ["AesGcmHkdfStreamingKeyManager.java"],
+ deps = [
+ ":streaming_aead_util",
+ "//proto:aes_gcm_hkdf_streaming_java_proto",
+ "//proto:common_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_hkdf_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "aes_ctr_hmac_streaming_key_manager",
+ srcs = ["AesCtrHmacStreamingKeyManager.java"],
+ deps = [
+ ":streaming_aead_util",
+ "//proto:aes_ctr_hmac_streaming_java_proto",
+ "//proto:common_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_hmac_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+java_library(
+ name = "readable_byte_channel_decrypter",
+ srcs = ["ReadableByteChannelDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:rewindable_readable_byte_channel",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+java_library(
+ name = "streaming_aead_wrapper",
+ srcs = ["StreamingAeadWrapper.java"],
+ deps = [
+ ":streaming_aead_helper",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+# Android libraries
+
+android_library(
+ name = "streaming_aead_util-android",
+ srcs = ["StreamingAeadUtil.java"],
+ deps = ["//proto:common_java_proto_lite"],
+)
+
+android_library(
+ name = "streaming_aead_key_templates-android",
+ srcs = ["StreamingAeadKeyTemplates.java"],
+ deps = [
+ ":aes_ctr_hmac_streaming_key_manager-android",
+ ":aes_gcm_hkdf_streaming_key_manager-android",
+ "//proto:aes_ctr_hmac_streaming_java_proto_lite",
+ "//proto:aes_gcm_hkdf_streaming_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ ],
+)
+
+android_library(
+ name = "streaming_aead_config-android",
+ srcs = ["StreamingAeadConfig.java"],
+ deps = [
+ ":aes_ctr_hmac_streaming_key_manager-android",
+ ":aes_gcm_hkdf_streaming_key_manager-android",
+ ":streaming_aead_wrapper-android",
+ "//proto:config_java_proto_lite",
+ ],
+)
+
+android_library(
+ name = "seekable_byte_channel_decrypter-android",
+ srcs = ["SeekableByteChannelDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+android_library(
+ name = "input_stream_decrypter-android",
+ srcs = ["InputStreamDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+android_library(
+ name = "streaming_aead_helper-android",
+ srcs = ["StreamingAeadHelper.java"],
+ deps = [
+ ":input_stream_decrypter-android",
+ ":readable_byte_channel_decrypter-android",
+ ":seekable_byte_channel_decrypter-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+android_library(
+ name = "streaming_aead_factory-android",
+ srcs = ["StreamingAeadFactory.java"],
+ deps = [
+ ":streaming_aead_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:key_manager-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+android_library(
+ name = "aes_gcm_hkdf_streaming_key_manager-android",
+ srcs = ["AesGcmHkdfStreamingKeyManager.java"],
+ deps = [
+ ":streaming_aead_util-android",
+ "//proto:aes_gcm_hkdf_streaming_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_hkdf_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "aes_ctr_hmac_streaming_key_manager-android",
+ srcs = ["AesCtrHmacStreamingKeyManager.java"],
+ deps = [
+ ":streaming_aead_util-android",
+ "//proto:aes_ctr_hmac_streaming_java_proto_lite",
+ "//proto:common_java_proto_lite",
+ "//proto:hmac_java_proto_lite",
+ "//proto:tink_java_proto_lite",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_hmac_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "@com_google_protobuf//:protobuf_javalite",
+ ],
+)
+
+android_library(
+ name = "readable_byte_channel_decrypter-android",
+ srcs = ["ReadableByteChannelDecrypter.java"],
+ deps = [
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:rewindable_readable_byte_channel",
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+android_library(
+ name = "streaming_aead_wrapper-android",
+ srcs = ["StreamingAeadWrapper.java"],
+ deps = [
+ ":streaming_aead_helper-android",
+ "//src/main/java/com/google/crypto/tink:primitive_set-android",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+# Deprecated, will be removed soon.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/streamingaead/ReadableByteChannelDecrypter.java b/java_src/src/main/java/com/google/crypto/tink/streamingaead/ReadableByteChannelDecrypter.java
index ed3c2fe..273d361 100644
--- a/java_src/src/main/java/com/google/crypto/tink/streamingaead/ReadableByteChannelDecrypter.java
+++ b/java_src/src/main/java/com/google/crypto/tink/streamingaead/ReadableByteChannelDecrypter.java
@@ -64,9 +64,7 @@
this.associatedData = associatedData.clone();
}
- @SuppressWarnings("GuardedBy")
@Override
- @GuardedBy("this")
public synchronized int read(ByteBuffer dst) throws IOException {
if (dst.remaining() == 0) {
return 0;
@@ -87,8 +85,6 @@
if (retValue > 0) {
// Found a matching channel
matchingChannel = attemptedChannel;
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead
- // found: 'this'
ciphertextChannel.disableRewinding();
} else if (retValue == 0) {
// Not clear whether the channel could be matched: it might be
@@ -96,8 +92,6 @@
// to check the header, or maybe the header was checked, but there
// were no actual encrypted bytes in the channel yet.
// Should try again.
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead
- // found: 'this'
ciphertextChannel.rewind();
attemptedMatching = false;
}
@@ -107,14 +101,10 @@
// IOException is thrown e.g. when MAC is incorrect, but also in case
// of I/O failures.
// TODO(b/66098906): Use a subclass of IOException.
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead
- // found: 'this'
ciphertextChannel.rewind();
continue;
} catch (GeneralSecurityException e) {
// Try another key.
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead
- // found: 'this'
ciphertextChannel.rewind();
continue;
}
@@ -123,21 +113,13 @@
}
}
- @SuppressWarnings("GuardedBy")
@Override
- @GuardedBy("this")
public synchronized void close() throws IOException {
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead found:
- // 'this'
ciphertextChannel.close();
}
- @SuppressWarnings("GuardedBy")
@Override
- @GuardedBy("this")
public synchronized boolean isOpen() {
- // TODO(b/145386688): This access should be guarded by 'this.ciphertextChannel'; instead found:
- // 'this'
return ciphertextChannel.isOpen();
}
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/streamingaead/StreamingAeadConfig.java b/java_src/src/main/java/com/google/crypto/tink/streamingaead/StreamingAeadConfig.java
index 7994922..5547062 100644
--- a/java_src/src/main/java/com/google/crypto/tink/streamingaead/StreamingAeadConfig.java
+++ b/java_src/src/main/java/com/google/crypto/tink/streamingaead/StreamingAeadConfig.java
@@ -16,13 +16,13 @@
package com.google.crypto.tink.streamingaead;
-import com.google.crypto.tink.Registry;
import com.google.crypto.tink.proto.RegistryConfig;
import java.security.GeneralSecurityException;
/**
- * Static methods and constants for registering with the {@link Registry} all instances of {@link
- * com.google.crypto.tink.StreamingAead} key types supported in a particular release of Tink.
+ * Static methods and constants for registering with the {@link com.google.crypto.tink.Registry} all
+ * instances of {@link com.google.crypto.tink.StreamingAead} key types supported in a particular
+ * release of Tink.
*
* <p>To register all StreamingAead key types provided in the latest Tink version one can do:
*
@@ -57,7 +57,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle StreamingAead key types supported in Tink.
*
* @deprecated use {@link #register}
@@ -68,7 +68,7 @@
}
/**
- * Tries to register with the {@link Registry} all instances of {@link
+ * Tries to register with the {@link com.google.crypto.tink.Registry} all instances of {@link
* com.google.crypto.tink.Catalogue} needed to handle StreamingAead key types supported in Tink.
*
* @since 1.2.0
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/AesGcmHkdfStreaming.java b/java_src/src/main/java/com/google/crypto/tink/subtle/AesGcmHkdfStreaming.java
index 59eda8a..17252b1 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/AesGcmHkdfStreaming.java
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/AesGcmHkdfStreaming.java
@@ -173,16 +173,17 @@
return Random.randBytes(keySizeInBytes);
}
- private GCMParameterSpec paramsForSegment(byte[] prefix, int segmentNr, boolean last) {
+ private static GCMParameterSpec paramsForSegment(byte[] prefix, long segmentNr, boolean last)
+ throws GeneralSecurityException {
ByteBuffer nonce = ByteBuffer.allocate(NONCE_SIZE_IN_BYTES);
nonce.order(ByteOrder.BIG_ENDIAN);
nonce.put(prefix);
- nonce.putInt(segmentNr);
+ SubtleUtil.putAsUnsigedInt(nonce, segmentNr);
nonce.put((byte) (last ? 1 : 0));
return new GCMParameterSpec(8 * TAG_SIZE_IN_BYTES, nonce.array());
}
- private byte[] randomNonce() {
+ private static byte[] randomNonce() {
return Random.randBytes(NONCE_PREFIX_IN_BYTES);
}
@@ -201,8 +202,8 @@
private final SecretKeySpec keySpec;
private final Cipher cipher;
private final byte[] noncePrefix;
- private ByteBuffer header;
- private int encryptedSegments = 0;
+ private final ByteBuffer header;
+ private long encryptedSegments = 0;
public AesGcmHkdfStreamEncrypter(byte[] aad) throws GeneralSecurityException {
cipher = cipherInstance();
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel
index c70a509..d71f0c9 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel
@@ -2,17 +2,510 @@
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
-filegroup(
- name = "srcs",
- srcs = glob(
- [
- "*.java",
- ],
- ),
+java_library(
+ name = "aes_cmac",
+ srcs = ["AesCmac.java"],
+ deps = [
+ ":aes_util",
+ ":bytes",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:mac",
+ ],
)
+java_library(
+ name = "aes_ctr_hmac_streaming",
+ srcs = ["AesCtrHmacStreaming.java"],
+ deps = [
+ ":bytes",
+ ":hkdf",
+ ":nonce_based_streaming_aead_cluster",
+ ":random",
+ ":stream_segment_decrypter",
+ ":stream_segment_encrypter",
+ ":subtle_util_cluster",
+ ":validators",
+ ],
+)
+
+java_library(
+ name = "cha_cha20_poly1305",
+ srcs = ["ChaCha20Poly1305.java"],
+ deps = [
+ ":cha_cha20",
+ ":cha_cha20_base",
+ ":cha_cha20_poly1305_base",
+ ],
+)
+
+java_library(
+ name = "stream_segment_decrypter",
+ srcs = ["StreamSegmentDecrypter.java"],
+)
+
+java_library(
+ name = "aes_ctr_jce_cipher",
+ srcs = ["AesCtrJceCipher.java"],
+ deps = [
+ ":ind_cpa_cipher",
+ ":random",
+ ":subtle_util_cluster",
+ ":validators",
+ ],
+)
+
+java_library(
+ name = "x25519",
+ srcs = ["X25519.java"],
+ # TODO(thaidn): remove this export once java_src/src/test:testlib has been build cleaned.
+ exports = [
+ ":field25519",
+ ],
+ deps = [
+ ":curve25519",
+ ":field25519",
+ ":random",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ ],
+)
+
+java_library(
+ name = "ecies_hkdf_sender_kem",
+ srcs = ["EciesHkdfSenderKem.java"],
+ deps = [
+ ":elliptic_curves",
+ ":hkdf",
+ ":immutable_byte_array",
+ ],
+)
+
+java_library(
+ name = "aes_util",
+ srcs = ["AesUtil.java"],
+)
+
+java_library(
+ name = "pem_key_type",
+ srcs = ["PemKeyType.java"],
+ deps = [
+ ":base64",
+ ":elliptic_curves",
+ ":enums",
+ ":subtle_util_cluster",
+ ],
+)
+
+java_library(
+ name = "aes_gcm_hkdf_streaming",
+ srcs = ["AesGcmHkdfStreaming.java"],
+ deps = [
+ ":hkdf",
+ ":nonce_based_streaming_aead_cluster",
+ ":random",
+ ":stream_segment_decrypter",
+ ":stream_segment_encrypter",
+ ":subtle_util_cluster",
+ ":validators",
+ ],
+)
+
+java_library(
+ name = "encrypt_then_authenticate",
+ srcs = ["EncryptThenAuthenticate.java"],
+ deps = [
+ ":aes_ctr_jce_cipher",
+ ":bytes",
+ ":ind_cpa_cipher",
+ ":prf_hmac_jce",
+ ":prf_mac",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:mac",
+ ],
+)
+
+java_library(
+ name = "bytes",
+ srcs = ["Bytes.java"],
+)
+
+java_library(
+ name = "immutable_byte_array",
+ srcs = ["ImmutableByteArray.java"],
+)
+
+java_library(
+ name = "elliptic_curves",
+ srcs = ["EllipticCurves.java"],
+ deps = [":subtle_util_cluster"],
+)
+
+java_library(
+ name = "ecies_aead_hkdf_dem_helper",
+ srcs = ["EciesAeadHkdfDemHelper.java"],
+ deps = ["//src/main/java/com/google/crypto/tink:aead"],
+)
+
+java_library(
+ name = "rsa_ssa_pkcs1_verify_jce",
+ srcs = ["RsaSsaPkcs1VerifyJce.java"],
+ deps = [
+ ":bytes",
+ ":enums",
+ ":hex",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ ],
+)
+
+java_library(
+ name = "ecies_aead_hkdf_hybrid_encrypt",
+ srcs = ["EciesAeadHkdfHybridEncrypt.java"],
+ deps = [
+ ":ecies_aead_hkdf_dem_helper",
+ ":ecies_hkdf_sender_kem",
+ ":elliptic_curves",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ ],
+)
+
+java_library(
+ name = "ecdsa_sign_jce",
+ srcs = ["EcdsaSignJce.java"],
+ deps = [
+ ":elliptic_curves",
+ ":enums",
+ ":subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ ],
+)
+
+java_library(
+ name = "validators",
+ srcs = ["Validators.java"],
+ deps = [":enums"],
+)
+
+java_library(
+ name = "stream_segment_encrypter",
+ srcs = ["StreamSegmentEncrypter.java"],
+)
+
+java_library(
+ name = "aes_siv",
+ srcs = ["AesSiv.java"],
+ deps = [
+ ":aes_cmac",
+ ":aes_util",
+ ":bytes",
+ ":subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ ],
+)
+
+java_library(
+ name = "ind_cpa_cipher",
+ srcs = ["IndCpaCipher.java"],
+)
+
+java_library(
+ name = "engine_wrapper",
+ srcs = ["EngineWrapper.java"],
+)
+
+java_library(
+ name = "prf_mac",
+ srcs = ["PrfMac.java"],
+ deps = [
+ ":bytes",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink/prf:prf_set",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pss_verify_jce",
+ srcs = ["RsaSsaPssVerifyJce.java"],
+ deps = [
+ ":bytes",
+ ":enums",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ ],
+)
+
+java_library(
+ name = "random",
+ srcs = ["Random.java"],
+)
+
+java_library(
+ name = "cha_cha20_base",
+ srcs = ["ChaCha20Base.java"],
+ deps = [
+ ":bytes",
+ ":ind_cpa_cipher",
+ ":random",
+ ],
+)
+
+java_library(
+ name = "poly1305",
+ srcs = ["Poly1305.java"],
+ deps = [":bytes"],
+)
+
+java_library(
+ name = "aes_gcm_jce",
+ srcs = ["AesGcmJce.java"],
+ deps = [
+ ":random",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:aead",
+ ],
+)
+
+java_library(
+ name = "hex",
+ srcs = ["Hex.java"],
+)
+
+java_library(
+ name = "ed25519_sign",
+ srcs = ["Ed25519Sign.java"],
+ deps = [
+ ":ed25519_cluster",
+ ":field25519",
+ ":random",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ ],
+)
+
+java_library(
+ name = "ecies_hkdf_recipient_kem",
+ srcs = ["EciesHkdfRecipientKem.java"],
+ deps = [
+ ":elliptic_curves",
+ ":hkdf",
+ ],
+)
+
+java_library(
+ name = "enums",
+ srcs = ["Enums.java"],
+)
+
+java_library(
+ name = "aes_eax_jce",
+ srcs = ["AesEaxJce.java"],
+ deps = [
+ ":random",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:aead",
+ ],
+)
+
+java_library(
+ name = "ed25519_verify",
+ srcs = ["Ed25519Verify.java"],
+ deps = [
+ ":ed25519_cluster",
+ ":field25519",
+ ":immutable_byte_array",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ ],
+)
+
+java_library(
+ name = "cha_cha20_poly1305_base",
+ srcs = ["ChaCha20Poly1305Base.java"],
+ deps = [
+ ":cha_cha20_base",
+ ":poly1305",
+ "//src/main/java/com/google/crypto/tink:aead",
+ ],
+)
+
+java_library(
+ name = "x_cha_cha20",
+ srcs = ["XChaCha20.java"],
+ deps = [":cha_cha20_base"],
+)
+
+java_library(
+ name = "rsa_ssa_pkcs1_sign_jce",
+ srcs = ["RsaSsaPkcs1SignJce.java"],
+ deps = [
+ ":enums",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ ],
+)
+
+java_library(
+ name = "field25519",
+ srcs = ["Field25519.java"],
+ deps = ["//src/main/java/com/google/crypto/tink/annotations:alpha"],
+)
+
+java_library(
+ name = "cha_cha20",
+ srcs = ["ChaCha20.java"],
+ deps = [":cha_cha20_base"],
+)
+
+java_library(
+ name = "ecdsa_verify_jce",
+ srcs = ["EcdsaVerifyJce.java"],
+ deps = [
+ ":elliptic_curves",
+ ":enums",
+ ":subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ ],
+)
+
+java_library(
+ name = "rewindable_readable_byte_channel",
+ srcs = ["RewindableReadableByteChannel.java"],
+ deps = [
+ "@maven//:com_google_code_findbugs_jsr305",
+ ],
+)
+
+java_library(
+ name = "hkdf",
+ srcs = ["Hkdf.java"],
+ deps = [
+ ":bytes",
+ ":subtle_util_cluster",
+ ],
+)
+
+java_library(
+ name = "rsa_ssa_pss_sign_jce",
+ srcs = ["RsaSsaPssSignJce.java"],
+ deps = [
+ ":enums",
+ ":random",
+ ":subtle_util_cluster",
+ ":validators",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ ],
+)
+
+java_library(
+ name = "base64",
+ srcs = ["Base64.java"],
+)
+
+java_library(
+ name = "prf_hmac_jce",
+ srcs = ["PrfHmacJce.java"],
+ deps = [
+ ":subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/prf:prf_set",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+java_library(
+ name = "kwp",
+ srcs = ["Kwp.java"],
+ deps = [
+ ":subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink:key_wrap",
+ ],
+)
+
+java_library(
+ name = "x_cha_cha20_poly1305",
+ srcs = ["XChaCha20Poly1305.java"],
+ deps = [
+ ":cha_cha20_base",
+ ":cha_cha20_poly1305_base",
+ ":x_cha_cha20",
+ ],
+)
+
+java_library(
+ name = "ecies_aead_hkdf_hybrid_decrypt",
+ srcs = ["EciesAeadHkdfHybridDecrypt.java"],
+ deps = [
+ ":ecies_aead_hkdf_dem_helper",
+ ":ecies_hkdf_recipient_kem",
+ ":elliptic_curves",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ ],
+)
+
+java_library(
+ name = "curve25519",
+ srcs = ["Curve25519.java"],
+ deps = [
+ ":bytes",
+ ":field25519",
+ ":hex",
+ "//src/main/java/com/google/crypto/tink/annotations:alpha",
+ ],
+)
+
+java_library(
+ name = "nonce_based_streaming_aead_cluster",
+ srcs = [
+ "NonceBasedStreamingAead.java",
+ "StreamingAeadDecryptingChannel.java",
+ "StreamingAeadDecryptingStream.java",
+ "StreamingAeadEncryptingChannel.java",
+ "StreamingAeadEncryptingStream.java",
+ "StreamingAeadSeekableDecryptingChannel.java",
+ ],
+ deps = [
+ ":stream_segment_decrypter",
+ ":stream_segment_encrypter",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ ],
+)
+
+java_library(
+ name = "subtle_util_cluster",
+ srcs = [
+ "EngineFactory.java",
+ "SubtleUtil.java",
+ ],
+ deps = [
+ ":engine_wrapper",
+ ":enums",
+ ":validators",
+ ],
+)
+
+java_library(
+ name = "ed25519_cluster",
+ srcs = [
+ "Ed25519.java",
+ "Ed25519Constants.java",
+ ],
+ deps = [
+ ":bytes",
+ ":curve25519",
+ ":field25519",
+ ":subtle_util_cluster",
+ ],
+)
+
+# Deprecated rules, will be deleted soon.
+
# common subtle
java_library(
@@ -57,7 +550,6 @@
":mac",
":subtle",
"//src/main/java/com/google/crypto/tink:primitives",
- "//src/main/java/com/google/crypto/tink/annotations",
],
)
@@ -83,13 +575,15 @@
srcs = [
"AesCmac.java",
"AesUtil.java",
- "MacJce.java",
+ "PrfHmacJce.java",
+ "PrfMac.java",
],
javacopts = JAVACOPTS_OSS,
deps = [
":subtle",
"//src/main/java/com/google/crypto/tink:primitives",
"//src/main/java/com/google/crypto/tink/annotations",
+ "//src/main/java/com/google/crypto/tink/prf:prf_set",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
@@ -112,6 +606,7 @@
],
javacopts = JAVACOPTS_OSS,
deps = [
+ ":curve25519",
":subtle",
":x25519",
"//src/main/java/com/google/crypto/tink:primitives",
@@ -176,19 +671,3 @@
"@maven//:com_google_code_findbugs_jsr305",
],
)
-
-# x25519 subtle
-
-java_library(
- name = "x25519",
- srcs = [
- "Curve25519.java",
- "Field25519.java",
- "X25519.java",
- ],
- javacopts = JAVACOPTS_OSS,
- deps = [
- ":subtle",
- "//src/main/java/com/google/crypto/tink/annotations",
- ],
-)
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/EncryptThenAuthenticate.java b/java_src/src/main/java/com/google/crypto/tink/subtle/EncryptThenAuthenticate.java
index 13911f7..b34ce04 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/EncryptThenAuthenticate.java
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/EncryptThenAuthenticate.java
@@ -52,7 +52,7 @@
throws GeneralSecurityException {
IndCpaCipher cipher = new AesCtrJceCipher(aesCtrKey, ivSize);
SecretKeySpec hmacKeySpec = new SecretKeySpec(hmacKey, "HMAC");
- Mac hmac = new MacJce(hmacAlgorithm, hmacKeySpec, tagSize);
+ Mac hmac = new PrfMac(new PrfHmacJce(hmacAlgorithm, hmacKeySpec), tagSize);
return new EncryptThenAuthenticate(cipher, hmac, tagSize);
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/MacJce.java b/java_src/src/main/java/com/google/crypto/tink/subtle/MacJce.java
deleted file mode 100644
index e842940..0000000
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/MacJce.java
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2017 Google Inc.
-//
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.google.crypto.tink.subtle;
-
-import com.google.crypto.tink.Mac;
-import com.google.errorprone.annotations.Immutable;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.NoSuchAlgorithmException;
-
-/**
- * {@link Mac} implementations in JCE.
- *
- * @since 1.0.0
- */
-@Immutable
-public final class MacJce implements Mac {
- static final int MIN_TAG_SIZE_IN_BYTES = 10;
- static final int MIN_KEY_SIZE_IN_BYTES = 16;
-
- @SuppressWarnings("Immutable") // We do not mutate the underlying mac.
- private final javax.crypto.Mac mac;
-
- private final int digestSize;
- private final String algorithm;
- @SuppressWarnings("Immutable") // We do not mutate the key.
- private final java.security.Key key;
-
- public MacJce(String algorithm, java.security.Key key, int digestSize)
- throws GeneralSecurityException {
- if (digestSize < MIN_TAG_SIZE_IN_BYTES) {
- throw new InvalidAlgorithmParameterException(
- "tag size too small, need at least " + MIN_TAG_SIZE_IN_BYTES + " bytes");
- }
- if (key.getEncoded().length < MIN_KEY_SIZE_IN_BYTES) {
- throw new InvalidAlgorithmParameterException(
- "key size too small, need at least " + MIN_KEY_SIZE_IN_BYTES + " bytes");
- }
- switch (algorithm) {
- case "HMACSHA1":
- if (digestSize > 20) {
- throw new InvalidAlgorithmParameterException("tag size too big");
- }
- break;
- case "HMACSHA256":
- if (digestSize > 32) {
- throw new InvalidAlgorithmParameterException("tag size too big");
- }
- break;
- case "HMACSHA512":
- if (digestSize > 64) {
- throw new InvalidAlgorithmParameterException("tag size too big");
- }
- break;
- default:
- throw new NoSuchAlgorithmException("unknown Hmac algorithm: " + algorithm);
- }
-
- this.algorithm = algorithm;
- this.digestSize = digestSize;
- this.key = key;
- this.mac = EngineFactory.MAC.getInstance(algorithm);
- mac.init(key);
- }
-
- @Override
- public byte[] computeMac(final byte[] data) throws GeneralSecurityException {
- javax.crypto.Mac tmp;
- try {
- // Cloning a mac is frequently fast and thread-safe.
- tmp = (javax.crypto.Mac) this.mac.clone();
- } catch (java.lang.CloneNotSupportedException ex) {
- // Unfortunately, the Mac interface in certain versions of Android is not clonable.
- tmp = EngineFactory.MAC.getInstance(this.algorithm);
- tmp.init(this.key);
- }
- tmp.update(data);
- byte[] digest = new byte[digestSize];
- System.arraycopy(tmp.doFinal(), 0, digest, 0, digestSize);
- return digest;
- }
-
- @Override
- public void verifyMac(final byte[] mac, final byte[] data) throws GeneralSecurityException {
- if (!Bytes.equal(computeMac(data), mac)) {
- throw new GeneralSecurityException("invalid MAC");
- }
- }
-}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/PrfHmacJce.java b/java_src/src/main/java/com/google/crypto/tink/subtle/PrfHmacJce.java
new file mode 100644
index 0000000..8467b0a
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/PrfHmacJce.java
@@ -0,0 +1,94 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.subtle;
+
+import com.google.crypto.tink.prf.Prf;
+import com.google.errorprone.annotations.Immutable;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import javax.crypto.Mac;
+
+/** {@link Prf} implementation using JCE. */
+@Immutable
+public final class PrfHmacJce implements Prf {
+ static final int MIN_KEY_SIZE_IN_BYTES = 16;
+
+ // We do not mutate the underlying mac and it is bound to the containing PrfHmacJce instance.
+ @SuppressWarnings({"Immutable", "ThreadLocalUsage"})
+ private final ThreadLocal<Mac> localMac =
+ new ThreadLocal<Mac>() {
+ @Override
+ protected Mac initialValue() {
+ try {
+ Mac mac = EngineFactory.MAC.getInstance(algorithm);
+ mac.init(key);
+ return mac;
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ };
+
+ private final String algorithm;
+ @SuppressWarnings("Immutable") // We do not mutate the key.
+ private final java.security.Key key;
+
+ private final int maxOutputLength;
+
+ public PrfHmacJce(String algorithm, java.security.Key key) throws GeneralSecurityException {
+ this.algorithm = algorithm;
+ this.key = key;
+ if (key.getEncoded().length < MIN_KEY_SIZE_IN_BYTES) {
+ throw new InvalidAlgorithmParameterException(
+ "key size too small, need at least " + MIN_KEY_SIZE_IN_BYTES + " bytes");
+ }
+
+ switch (algorithm) {
+ case "HMACSHA1":
+ maxOutputLength = 20;
+ break;
+ case "HMACSHA256":
+ maxOutputLength = 32;
+ break;
+ case "HMACSHA512":
+ maxOutputLength = 64;
+ break;
+ default:
+ throw new NoSuchAlgorithmException("unknown Hmac algorithm: " + algorithm);
+ }
+
+ // Initialize the current threads mac, mostly to fail fast if anything is wrong.
+ localMac.get();
+ }
+
+ @Override
+ public byte[] compute(byte[] data, int outputLength) throws GeneralSecurityException {
+ if (outputLength > maxOutputLength) {
+ throw new InvalidAlgorithmParameterException("tag size too big");
+ }
+
+ localMac.get().update(data);
+ return Arrays.copyOf(localMac.get().doFinal(), outputLength);
+ }
+
+ /** Returns the maximum supported tag length. */
+ public int getMaxOutputLength() {
+ return maxOutputLength;
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/PrfMac.java b/java_src/src/main/java/com/google/crypto/tink/subtle/PrfMac.java
new file mode 100644
index 0000000..c52d672
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/PrfMac.java
@@ -0,0 +1,60 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.subtle;
+
+import com.google.crypto.tink.Mac;
+import com.google.crypto.tink.prf.Prf;
+import com.google.errorprone.annotations.Immutable;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * Class that provides the functionality expressed by the Mac primitive using a Prf implementation.
+ */
+@Immutable
+public class PrfMac implements Mac {
+ static final int MIN_TAG_SIZE_IN_BYTES = 10;
+
+ private final Prf wrappedPrf;
+ private final int tagSize;
+
+ /** Wrap {@code wrappedPrf } in a Mac primitive with the specified {@code tagSize} */
+ public PrfMac(Prf wrappedPrf, int tagSize) throws GeneralSecurityException {
+ this.wrappedPrf = wrappedPrf;
+ this.tagSize = tagSize;
+
+ // The output length is restricted by the HMAC spec. Check that first.
+ if (tagSize < MIN_TAG_SIZE_IN_BYTES) {
+ throw new InvalidAlgorithmParameterException(
+ "tag size too small, need at least " + MIN_TAG_SIZE_IN_BYTES + " bytes");
+ }
+
+ // Some Prf implementations have restrictions on maximum tag length. These throw on compute().
+ // Check for those restrictions on tag length here by doing a compute() pass.
+ wrappedPrf.compute(new byte[0], tagSize);
+ }
+
+ @Override
+ public byte[] computeMac(byte[] data) throws GeneralSecurityException {
+ return wrappedPrf.compute(data, tagSize);
+ }
+
+ @Override
+ public void verifyMac(byte[] mac, byte[] data) throws GeneralSecurityException {
+ if (!Bytes.equal(computeMac(data), mac)) {
+ throw new GeneralSecurityException("invalid MAC");
+ }
+ }
+}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/RewindableReadableByteChannel.java b/java_src/src/main/java/com/google/crypto/tink/subtle/RewindableReadableByteChannel.java
index 59c3165..8c354bb 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/RewindableReadableByteChannel.java
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/RewindableReadableByteChannel.java
@@ -57,7 +57,6 @@
* read()-calls will be forwarded directly to the wrapped
* channel (after the currently buffered bytes are read).
*/
- @GuardedBy("this")
public synchronized void disableRewinding() {
this.canRewind = false;
}
@@ -65,7 +64,6 @@
/**
* Rewinds this buffer to the beginning (if rewinding is still enabled).
*/
- @GuardedBy("this")
public synchronized void rewind() throws IOException {
if (!canRewind) {
throw new IOException("Cannot rewind anymore.");
@@ -76,7 +74,6 @@
}
@Override
- @GuardedBy("this")
public synchronized int read(ByteBuffer dst) throws IOException {
if (directRead) {
return baseChannel.read(dst);
@@ -148,7 +145,6 @@
}
@Override
- @GuardedBy("this")
public synchronized void close() throws IOException {
canRewind = false;
directRead = true;
@@ -156,7 +152,6 @@
}
@Override
- @GuardedBy("this")
public synchronized boolean isOpen() {
return baseChannel.isOpen();
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java b/java_src/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java
index cc8f8ab..6d82bf8 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java
@@ -154,7 +154,7 @@
}
/**
- * Inserts {@param value} as unsigned into into {@param buffer}.
+ * Inserts {@code value} as unsigned into into {@code buffer}.
*
* <p>@throws GeneralSecurityException if not 0 <= value < 2^32.
*/
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/Validators.java b/java_src/src/main/java/com/google/crypto/tink/subtle/Validators.java
index eafc4cf..3fe8921 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/Validators.java
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/Validators.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
+import java.util.Locale;
import java.util.regex.Pattern;
/**
@@ -29,6 +30,8 @@
* @since 1.0.0
*/
public final class Validators {
+ private Validators() {}
+
private static final String TYPE_URL_PREFIX = "type.googleapis.com/";
/**
* To reach 128-bit security strength, RSA's modulus must be at least 3072-bit while 2048-bit RSA
@@ -113,7 +116,7 @@
*/
public static void validateNotExists(File f) throws IOException {
if (f.exists()) {
- throw new IOException(String.format("%s exists, please choose another file\n", f.toString()));
+ throw new IOException(String.format("%s exists, please choose another file\n", f));
}
}
@@ -121,18 +124,17 @@
public static void validateExists(File f) throws IOException {
if (!f.exists()) {
throw new IOException(
- String.format("Error: %s doesn't exist, please choose another file\n", f.toString()));
+ String.format("Error: %s doesn't exist, please choose another file\n", f));
}
}
/**
* Validates that {@code kmsKeyUri} starts with {@code expectedPrefix}, and removes the prefix.
*
- * @throws IllegalArgumentException
+ * @throws IllegalArgumentException if {@code kmsKeyUri} is invalid.
*/
- public static String validateKmsKeyUriAndRemovePrefix(String expectedPrefix, String kmsKeyUri)
- throws IllegalArgumentException {
- if (!kmsKeyUri.toLowerCase().startsWith(expectedPrefix)) {
+ public static String validateKmsKeyUriAndRemovePrefix(String expectedPrefix, String kmsKeyUri) {
+ if (!kmsKeyUri.toLowerCase(Locale.US).startsWith(expectedPrefix)) {
throw new IllegalArgumentException(
String.format("key URI must start with %s", expectedPrefix));
}
diff --git a/java_src/src/main/java/com/google/crypto/tink/subtle/prf/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/subtle/prf/BUILD.bazel
index d535d13..ce3c182 100644
--- a/java_src/src/main/java/com/google/crypto/tink/subtle/prf/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/subtle/prf/BUILD.bazel
@@ -2,7 +2,7 @@
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
java_library(
name = "prf",
diff --git a/java_src/src/main/java/com/google/crypto/tink/testing/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/testing/BUILD.bazel
index 084feb2..68b9276 100644
--- a/java_src/src/main/java/com/google/crypto/tink/testing/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/testing/BUILD.bazel
@@ -4,7 +4,7 @@
package(
default_testonly = 1,
- default_visibility = ["//:__subpackages__"],
+ default_visibility = ["//visibility:public"],
)
java_library(
@@ -29,16 +29,18 @@
"//proto:rsa_ssa_pkcs1_java_proto",
"//proto:rsa_ssa_pss_java_proto",
"//proto:tink_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
"//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
- "//src/main/java/com/google/crypto/tink:core",
- "//src/main/java/com/google/crypto/tink:primitives",
- "//src/main/java/com/google/crypto/tink/aead",
- "//src/main/java/com/google/crypto/tink/daead",
- "//src/main/java/com/google/crypto/tink/hybrid",
- "//src/main/java/com/google/crypto/tink/mac",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_config",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates",
+ "//src/main/java/com/google/crypto/tink/mac:mac_config",
"//src/main/java/com/google/crypto/tink/prf:prf_config",
- "//src/main/java/com/google/crypto/tink/streamingaead",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:hex",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_truth_truth",
"@maven//:junit_junit",
@@ -66,16 +68,18 @@
"//proto:rsa_ssa_pkcs1_java_proto_lite",
"//proto:rsa_ssa_pss_java_proto_lite",
"//proto:tink_java_proto_lite",
- "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
- "//src/main/java/com/google/crypto/tink:core-android",
- "//src/main/java/com/google/crypto/tink:primitives",
- "//src/main/java/com/google/crypto/tink/aead:android",
- "//src/main/java/com/google/crypto/tink/daead:android",
- "//src/main/java/com/google/crypto/tink/hybrid:android",
- "//src/main/java/com/google/crypto/tink/mac:android",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle-android",
+ "//src/main/java/com/google/crypto/tink:registry_cluster-android",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config-android",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_config-android",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates-android",
+ "//src/main/java/com/google/crypto/tink/mac:mac_config-android",
"//src/main/java/com/google/crypto/tink/prf:prf_config-android",
- "//src/main/java/com/google/crypto/tink/streamingaead:android",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config-android",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:hex",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_truth_truth",
"@maven//:junit_junit",
@@ -88,8 +92,8 @@
javacopts = JAVACOPTS_OSS,
deps = [
":test_util",
- "//src/main/java/com/google/crypto/tink:primitives",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
"@maven//:junit_junit",
],
)
@@ -100,8 +104,8 @@
javacopts = JAVACOPTS_OSS,
deps = [
":test_util-android",
- "//src/main/java/com/google/crypto/tink:primitives",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
"@maven//:junit_junit",
],
)
@@ -111,7 +115,8 @@
srcs = ["KeyTypeManagerTestUtil.java"],
javacopts = JAVACOPTS_OSS,
deps = [
- "//src/main/java/com/google/crypto/tink:core",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_truth_truth",
],
@@ -122,7 +127,8 @@
srcs = ["KeyTypeManagerTestUtil.java"],
javacopts = JAVACOPTS_OSS,
deps = [
- "//src/main/java/com/google/crypto/tink:core",
+ "//src/main/java/com/google/crypto/tink:key_template-android",
+ "//src/main/java/com/google/crypto/tink:key_type_manager-android",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_truth_truth",
],
@@ -134,7 +140,8 @@
javacopts = JAVACOPTS_OSS,
deps = [
":test_util",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
"@maven//:org_json_json",
],
)
@@ -145,7 +152,8 @@
javacopts = JAVACOPTS_OSS,
deps = [
":test_util-android",
- "//src/main/java/com/google/crypto/tink/subtle",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
"@maven//:org_json_json",
],
)
diff --git a/java_src/src/main/java/com/google/crypto/tink/util/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/util/BUILD.bazel
index 2b94884..4b7e486 100644
--- a/java_src/src/main/java/com/google/crypto/tink/util/BUILD.bazel
+++ b/java_src/src/main/java/com/google/crypto/tink/util/BUILD.bazel
@@ -1,8 +1,36 @@
+load("@build_bazel_rules_android//android:rules.bzl", "android_library")
load("//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
licenses(["notice"])
-package(default_visibility = ["//:__subpackages__"])
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "keys_downloader",
+ srcs = ["KeysDownloader.java"],
+ deps = [
+ "@maven//:com_google_code_findbugs_jsr305",
+ "@maven//:com_google_http_client_google_http_client",
+ "@maven//:joda_time_joda_time",
+ ],
+)
+
+java_library(
+ name = "test_util",
+ srcs = ["TestUtil.java"],
+)
+
+android_library(
+ name = "keys_downloader-android",
+ srcs = ["KeysDownloader.java"],
+ deps = [
+ "@maven//:com_google_code_findbugs_jsr305",
+ "@maven//:com_google_http_client_google_http_client",
+ "@maven//:joda_time_joda_time",
+ ],
+)
+
+# Deprecated, will be removed.
filegroup(
name = "srcs",
diff --git a/java_src/src/main/java/com/google/crypto/tink/util/TestUtil.java b/java_src/src/main/java/com/google/crypto/tink/util/TestUtil.java
new file mode 100644
index 0000000..26e66b4
--- /dev/null
+++ b/java_src/src/main/java/com/google/crypto/tink/util/TestUtil.java
@@ -0,0 +1,143 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.util;
+
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+
+/** Provides various utility methods for testing. */
+public class TestUtil {
+
+ private TestUtil() {}
+
+ /**
+ * Uses a z test on the given byte string, expecting all bits to be uniformly set with probability
+ * 1/2. Returns non ok status if the z test fails by more than 10 standard deviations.
+ *
+ * <p>With less statistics jargon: This counts the number of bits set and expects the number to be
+ * roughly half of the length of the string. The law of large numbers suggests that we can assume
+ * that the longer the string is, the more accurate that estimate becomes for a random string.
+ * This test is useful to detect things like strings that are entirely zero.
+ *
+ * <p>Note: By itself, this is a very weak test for randomness.
+ *
+ * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally.
+ */
+ public static void ztestUniformString(byte[] string) throws GeneralSecurityException {
+ final double minAcceptableStdDevs = 10.0;
+ double totalBits = string.length * 8;
+ double expected = totalBits / 2.0;
+ double stddev = Math.sqrt(totalBits / 4.0);
+
+ // This test is very limited at low string lengths. Below a certain threshold it tests nothing.
+ if (expected < stddev * minAcceptableStdDevs) {
+ throw new GeneralSecurityException(
+ "Test will always succeed with strings of the given length "
+ + string.length
+ + ". Use more bytes.");
+ }
+
+ long numSetBits = 0;
+ for (byte b : string) {
+ int unsignedInt = toUnsignedInt(b);
+ // Counting the number of bits set in byte:
+ while (unsignedInt != 0) {
+ numSetBits++;
+ unsignedInt = (unsignedInt & (unsignedInt - 1));
+ }
+ }
+ // Check that the number of bits is within 10 stddevs.
+ if (Math.abs((double) numSetBits - expected) < minAcceptableStdDevs * stddev) {
+ return;
+ }
+ throw new GeneralSecurityException(
+ "Z test for uniformly distributed variable out of bounds; "
+ + "Actual number of set bits was "
+ + numSetBits
+ + " expected was "
+ + expected
+ + " 10 * standard deviation is 10 * "
+ + stddev
+ + " = "
+ + 10.0 * stddev);
+ }
+
+ /**
+ * Tests that the crosscorrelation of two strings of equal length points to independent and
+ * uniformly distributed strings. Returns non ok status if the z test fails by more than 10
+ * standard deviations.
+ *
+ * <p>With less statistics jargon: This xors two strings and then performs the ZTestUniformString
+ * on the result. If the two strings are independent and uniformly distributed, the xor'ed string
+ * is as well. A cross correlation test will find whether two strings overlap more or less than it
+ * would be expected.
+ *
+ * <p>Note: Having a correlation of zero is only a necessary but not sufficient condition for
+ * independence.
+ *
+ * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally.
+ */
+ public static void ztestCrossCorrelationUniformStrings(byte[] string1, byte[] string2)
+ throws GeneralSecurityException {
+ if (string1.length != string2.length) {
+ throw new GeneralSecurityException("Strings are not of equal length");
+ }
+ byte[] crossed = new byte[string1.length];
+ for (int i = 0; i < string1.length; i++) {
+ crossed[i] = (byte) (string1[i] ^ string2[i]);
+ }
+ ztestUniformString(crossed);
+ }
+
+ /**
+ * Tests that the autocorrelation of a string points to the bits being independent and uniformly
+ * distributed. Rotates the string in a cyclic fashion. Returns non ok status if the z test fails
+ * by more than 10 standard deviations.
+ *
+ * <p>With less statistics jargon: This rotates the string bit by bit and performs
+ * ZTestCrosscorrelationUniformStrings on each of the rotated strings and the original. This will
+ * find self similarity of the input string, especially periodic self similarity. For example, it
+ * is a decent test to find English text (needs about 180 characters with the current settings).
+ *
+ * <p>Note: Having a correlation of zero is only a necessary but not sufficient condition for
+ * independence.
+ *
+ * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally.
+ */
+ public static void ztestAutocorrelationUniformString(byte[] string)
+ throws GeneralSecurityException {
+ byte[] rotated = Arrays.copyOf(string, string.length);
+
+ for (int i = 1; i < string.length * 8; i++) {
+ rotate(rotated);
+ ztestCrossCorrelationUniformStrings(string, rotated);
+ }
+ }
+
+ /** Manual implementation of Byte.toUnsignedByte. The Android JDK does not have this method. */
+ private static int toUnsignedInt(byte b) {
+ return b & 0xff;
+ }
+
+ private static void rotate(byte[] string) {
+ byte[] ref = Arrays.copyOf(string, string.length);
+ for (int i = 0; i < string.length; i++) {
+ string[i] =
+ (byte)
+ ((toUnsignedInt(string[i]) >> 1)
+ | ((1 & toUnsignedInt(ref[(i == 0 ? string.length : i) - 1])) << 7));
+ }
+ }
+}
diff --git a/java_src/src/main/resources/META-INF/proguard/protobuf.pro b/java_src/src/main/resources/META-INF/proguard/protobuf.pro
new file mode 100644
index 0000000..b2508fc
--- /dev/null
+++ b/java_src/src/main/resources/META-INF/proguard/protobuf.pro
@@ -0,0 +1,14 @@
+# Recently Protobuf Javalite introduced a change that relies on reflection,
+# which doesn't work with Proguard. This rule keeps the reflection usages in
+# (shaded) Protobuf classes in Tink as-is.
+# The location of this file is determined by
+# - https://developer.android.com/studio/build/shrink-code#configuration-files
+# - https://docs.bazel.build/versions/master/be/java.html#java_library.resources
+# See also:
+# - https://github.com/google/tink/issues/361
+# - https://github.com/protocolbuffers/protobuf/issues/6463
+# WARNING: the shaded package name com.google.crypto.tink.shaded.protobuf must
+# be kept in sync with jar_jar_rules.txt.
+-keepclassmembers class * extends com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite {
+ <fields>;
+}
diff --git a/java_src/src/test/BUILD.bazel b/java_src/src/test/BUILD.bazel
index df4c0b1..71ecef0 100644
--- a/java_src/src/test/BUILD.bazel
+++ b/java_src/src/test/BUILD.bazel
@@ -9,19 +9,183 @@
"**/*.java",
]),
deps = [
- "//:awskms",
- "//:gcpkms",
- "//:testonly",
+ "//proto:aes_cmac_java_proto",
+ "//proto:aes_ctr_hmac_aead_java_proto",
+ "//proto:aes_ctr_hmac_streaming_java_proto",
+ "//proto:aes_ctr_java_proto",
+ "//proto:aes_eax_java_proto",
+ "//proto:aes_gcm_hkdf_streaming_java_proto",
+ "//proto:aes_gcm_java_proto",
+ "//proto:aes_siv_java_proto",
+ "//proto:chacha20_poly1305_java_proto",
+ "//proto:common_java_proto",
+ "//proto:config_java_proto",
+ "//proto:ecdsa_java_proto",
+ "//proto:ecies_aead_hkdf_java_proto",
+ "//proto:ed25519_java_proto",
+ "//proto:hkdf_prf_java_proto",
+ "//proto:hmac_java_proto",
+ "//proto:kms_aead_java_proto",
+ "//proto:kms_envelope_java_proto",
+ "//proto:prf_based_deriver_java_proto",
+ "//proto:rsa_ssa_pkcs1_java_proto",
+ "//proto:rsa_ssa_pss_java_proto",
+ "//proto:tink_java_proto",
+ "//proto:xchacha20_poly1305_java_proto",
+ "//src/main/java/com/google/crypto/tink:aead",
+ "//src/main/java/com/google/crypto/tink:binary_keyset_reader",
+ "//src/main/java/com/google/crypto/tink:binary_keyset_writer",
+ "//src/main/java/com/google/crypto/tink:catalogue",
+ "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "//src/main/java/com/google/crypto/tink:config",
+ "//src/main/java/com/google/crypto/tink:core",
+ "//src/main/java/com/google/crypto/tink:crypto_format",
+ "//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink:json_keyset_reader",
+ "//src/main/java/com/google/crypto/tink:json_keyset_writer",
+ "//src/main/java/com/google/crypto/tink:key_manager",
+ "//src/main/java/com/google/crypto/tink:key_manager_impl",
+ "//src/main/java/com/google/crypto/tink:key_template",
+ "//src/main/java/com/google/crypto/tink:key_type_manager",
+ "//src/main/java/com/google/crypto/tink:key_wrap",
+ "//src/main/java/com/google/crypto/tink:keyset_reader",
+ "//src/main/java/com/google/crypto/tink:keyset_writer",
+ "//src/main/java/com/google/crypto/tink:kms_client",
+ "//src/main/java/com/google/crypto/tink:kms_clients",
+ "//src/main/java/com/google/crypto/tink:mac",
+ "//src/main/java/com/google/crypto/tink:no_secret_keyset_handle",
+ "//src/main/java/com/google/crypto/tink:primitive_set",
+ "//src/main/java/com/google/crypto/tink:primitive_wrapper",
+ "//src/main/java/com/google/crypto/tink:private_key_manager",
+ "//src/main/java/com/google/crypto/tink:private_key_manager_impl",
+ "//src/main/java/com/google/crypto/tink:private_key_type_manager",
+ "//src/main/java/com/google/crypto/tink:public_key_sign",
+ "//src/main/java/com/google/crypto/tink:public_key_verify",
+ "//src/main/java/com/google/crypto/tink:registry_cluster",
+ "//src/main/java/com/google/crypto/tink:streaming_aead",
+ "//src/main/java/com/google/crypto/tink:util",
+ "//src/main/java/com/google/crypto/tink/aead:aead_config",
+ "//src/main/java/com/google/crypto/tink/aead:aead_key_templates",
+ "//src/main/java/com/google/crypto/tink/aead:aead_wrapper",
+ "//src/main/java/com/google/crypto/tink/aead:aes_ctr_hmac_aead_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:aes_ctr_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:aes_eax_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:aes_gcm_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:cha_cha20_poly1305_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:kms_aead_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:kms_envelope_aead_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead:x_cha_cha20_poly1305_key_manager",
+ "//src/main/java/com/google/crypto/tink/aead/subtle:aead_factory",
+ "//src/main/java/com/google/crypto/tink/aead/subtle:aes_gcm_factory",
+ "//src/main/java/com/google/crypto/tink/config:tink_config",
+ "//src/main/java/com/google/crypto/tink/daead:aes_siv_key_manager",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_config",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_factory",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_key_templates",
+ "//src/main/java/com/google/crypto/tink/daead:deterministic_aead_wrapper",
+ "//src/main/java/com/google/crypto/tink/hybrid:ecies_aead_hkdf_private_key_manager",
+ "//src/main/java/com/google/crypto/tink/hybrid:ecies_aead_hkdf_public_key_manager",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_config",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_decrypt_factory",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_decrypt_wrapper",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_encrypt_factory",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_encrypt_wrapper",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates",
+ "//src/main/java/com/google/crypto/tink/hybrid:hybrid_util",
+ "//src/main/java/com/google/crypto/tink/hybrid:registry_ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/hybrid/subtle:rsa_kem",
+ "//src/main/java/com/google/crypto/tink/hybrid/subtle:rsa_kem_hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink/hybrid/subtle:rsa_kem_hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink/integration/awskms:aws_kms_aead",
+ "//src/main/java/com/google/crypto/tink/integration/gcpkms:gcp_kms_client",
+ "//src/main/java/com/google/crypto/tink/mac:aes_cmac_key_manager",
+ "//src/main/java/com/google/crypto/tink/mac:hmac_key_manager",
+ "//src/main/java/com/google/crypto/tink/mac:mac_config",
+ "//src/main/java/com/google/crypto/tink/mac:mac_factory",
+ "//src/main/java/com/google/crypto/tink/mac:mac_key_templates",
+ "//src/main/java/com/google/crypto/tink/mac:mac_wrapper",
"//src/main/java/com/google/crypto/tink/prf:hkdf_prf_key_manager",
"//src/main/java/com/google/crypto/tink/prf:prf_config",
"//src/main/java/com/google/crypto/tink/prf:prf_key_templates",
"//src/main/java/com/google/crypto/tink/prf:prf_set",
"//src/main/java/com/google/crypto/tink/prf:prf_set_wrapper",
+ "//src/main/java/com/google/crypto/tink/signature:ecdsa_sign_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:ecdsa_verify_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:ed25519_private_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:ed25519_public_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:public_key_sign_factory",
+ "//src/main/java/com/google/crypto/tink/signature:public_key_sign_wrapper",
+ "//src/main/java/com/google/crypto/tink/signature:public_key_verify_factory",
+ "//src/main/java/com/google/crypto/tink/signature:public_key_verify_wrapper",
+ "//src/main/java/com/google/crypto/tink/signature:rsa_ssa_pkcs1_sign_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:rsa_ssa_pkcs1_verify_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:rsa_ssa_pss_sign_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:rsa_ssa_pss_verify_key_manager",
+ "//src/main/java/com/google/crypto/tink/signature:sig_util",
+ "//src/main/java/com/google/crypto/tink/signature:signature_config",
+ "//src/main/java/com/google/crypto/tink/signature:signature_key_templates",
+ "//src/main/java/com/google/crypto/tink/signature:signature_pem_keyset_reader",
+ "//src/main/java/com/google/crypto/tink/streamingaead:aes_ctr_hmac_streaming_key_manager",
+ "//src/main/java/com/google/crypto/tink/streamingaead:aes_gcm_hkdf_streaming_key_manager",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_config",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_factory",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_key_templates",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_util",
+ "//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_wrapper",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_cmac",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_hmac_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_ctr_jce_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_eax_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_hkdf_streaming",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_gcm_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_siv",
+ "//src/main/java/com/google/crypto/tink/subtle:aes_util",
+ "//src/main/java/com/google/crypto/tink/subtle:bytes",
+ "//src/main/java/com/google/crypto/tink/subtle:cha_cha20",
+ "//src/main/java/com/google/crypto/tink/subtle:cha_cha20_poly1305",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:ecdsa_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_dem_helper",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_decrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:ecies_aead_hkdf_hybrid_encrypt",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_sign",
+ "//src/main/java/com/google/crypto/tink/subtle:ed25519_verify",
+ "//src/main/java/com/google/crypto/tink/subtle:elliptic_curves",
+ "//src/main/java/com/google/crypto/tink/subtle:encrypt_then_authenticate",
+ "//src/main/java/com/google/crypto/tink/subtle:enums",
+ "//src/main/java/com/google/crypto/tink/subtle:field25519",
+ "//src/main/java/com/google/crypto/tink/subtle:hex",
+ "//src/main/java/com/google/crypto/tink/subtle:hkdf",
+ "//src/main/java/com/google/crypto/tink/subtle:immutable_byte_array",
+ "//src/main/java/com/google/crypto/tink/subtle:ind_cpa_cipher",
+ "//src/main/java/com/google/crypto/tink/subtle:kwp",
+ "//src/main/java/com/google/crypto/tink/subtle:pem_key_type",
+ "//src/main/java/com/google/crypto/tink/subtle:poly1305",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_hmac_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:prf_mac",
+ "//src/main/java/com/google/crypto/tink/subtle:random",
+ "//src/main/java/com/google/crypto/tink/subtle:rewindable_readable_byte_channel",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pkcs1_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_sign_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:rsa_ssa_pss_verify_jce",
+ "//src/main/java/com/google/crypto/tink/subtle:subtle_util_cluster",
+ "//src/main/java/com/google/crypto/tink/subtle:validators",
+ "//src/main/java/com/google/crypto/tink/subtle:x25519",
+ "//src/main/java/com/google/crypto/tink/subtle:x_cha_cha20",
+ "//src/main/java/com/google/crypto/tink/subtle:x_cha_cha20_poly1305",
+ "//src/main/java/com/google/crypto/tink/subtle/prf:hkdf_streaming_prf",
"//src/main/java/com/google/crypto/tink/subtle/prf:prf_impl",
+ "//src/main/java/com/google/crypto/tink/subtle/prf:streaming_prf",
"//src/main/java/com/google/crypto/tink/testing:key_type_manager_test_util",
"//src/main/java/com/google/crypto/tink/testing:streaming_test_util",
"//src/main/java/com/google/crypto/tink/testing:test_util",
"//src/main/java/com/google/crypto/tink/testing:wycheproof_test_util",
+ "//src/main/java/com/google/crypto/tink/util:keys_downloader",
+ "//src/main/java/com/google/crypto/tink/util:test_util",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_amazonaws_aws_java_sdk_core",
"@maven//:com_amazonaws_aws_java_sdk_kms",
diff --git a/java_src/src/test/java/com/google/crypto/tink/KeysetHandleTest.java b/java_src/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
index f26902f..0b5bc66 100644
--- a/java_src/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
@@ -32,6 +32,7 @@
import com.google.crypto.tink.proto.AesGcmKeyFormat;
import com.google.crypto.tink.proto.EcdsaPrivateKey;
import com.google.crypto.tink.proto.KeyData;
+import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.proto.KeyStatusType;
import com.google.crypto.tink.proto.Keyset;
import com.google.crypto.tink.proto.OutputPrefixType;
@@ -42,7 +43,9 @@
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil;
import com.google.crypto.tink.testing.TestUtil.DummyAead;
+import com.google.protobuf.ByteString;
import com.google.protobuf.ExtensionRegistryLite;
+import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.GeneralSecurityException;
@@ -56,6 +59,39 @@
/** Tests for KeysetHandle. */
@RunWith(JUnit4.class)
public class KeysetHandleTest {
+ /**
+ * A KeyTypeManager for testing. It accepts AesGcmKeys and produces primitives as with the passed
+ * in factory.
+ */
+ public static class TestKeyTypeManager extends KeyTypeManager<AesGcmKey> {
+ public TestKeyTypeManager(PrimitiveFactory<?, AesGcmKey>... factories) {
+ super(AesGcmKey.class, factories);
+ }
+
+ @Override
+ public String getKeyType() {
+ return "type.googleapis.com/google.crypto.tink.AesGcmKey";
+ }
+
+ @Override
+ public int getVersion() {
+ return 1;
+ }
+
+ @Override
+ public KeyMaterialType keyMaterialType() {
+ return KeyMaterialType.SYMMETRIC;
+ }
+
+ @Override
+ public void validateKey(AesGcmKey keyProto) {}
+
+ @Override
+ public AesGcmKey parseKey(ByteString byteString) throws InvalidProtocolBufferException {
+ return AesGcmKey.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry());
+ }
+ }
+
@BeforeClass
public static void setUp() throws GeneralSecurityException {
Config.register(TinkConfig.TINK_1_0_0);
@@ -287,9 +323,8 @@
// always fails.
KeyManager<Aead> manager =
new KeyManagerImpl<>(
- new KeyTypeManagerTest.TestKeyTypeManager(
- new KeyTypeManagerTest.TestKeyTypeManager.PrimitiveFactory<Aead, AesGcmKey>(
- Aead.class) {
+ new TestKeyTypeManager(
+ new KeyTypeManager.PrimitiveFactory<Aead, AesGcmKey>(Aead.class) {
@Override
public Aead getPrimitive(AesGcmKey key) {
return new DummyAead();
diff --git a/java_src/src/test/java/com/google/crypto/tink/RegistryTest.java b/java_src/src/test/java/com/google/crypto/tink/RegistryTest.java
index 53ad42d..3891a27 100644
--- a/java_src/src/test/java/com/google/crypto/tink/RegistryTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/RegistryTest.java
@@ -44,7 +44,7 @@
import com.google.crypto.tink.subtle.AesEaxJce;
import com.google.crypto.tink.subtle.AesGcmJce;
import com.google.crypto.tink.subtle.EncryptThenAuthenticate;
-import com.google.crypto.tink.subtle.MacJce;
+import com.google.crypto.tink.subtle.PrfMac;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil.DummyAead;
import com.google.protobuf.ByteString;
@@ -158,7 +158,7 @@
fail("Expected ClassCastException");
} catch (ClassCastException e) {
assertExceptionContains(e, "com.google.crypto.tink.Aead");
- assertExceptionContains(e, "com.google.crypto.tink.subtle.MacJce");
+ assertExceptionContains(e, "com.google.crypto.tink.subtle.PrfMac");
}
}
@@ -386,7 +386,7 @@
assertThat(hmacKey.getParams().getHash()).isEqualTo(HashType.SHA256);
assertThat(hmacKeyData.getTypeUrl()).isEqualTo(MacConfig.HMAC_TYPE_URL);
// This might break when we add native implementations.
- assertThat(mac.getClass()).isEqualTo(MacJce.class);
+ assertThat(mac.getClass()).isEqualTo(PrfMac.class);
}
@Test
@@ -401,7 +401,7 @@
assertThat(hmacKey.getParams().getHash()).isEqualTo(HashType.SHA256);
assertThat(hmacKeyData.getTypeUrl()).isEqualTo(MacConfig.HMAC_TYPE_URL);
// This might break when we add native implementations.
- assertThat(mac.getClass()).isEqualTo(MacJce.class);
+ assertThat(mac.getClass()).isEqualTo(PrfMac.class);
}
@Test
diff --git a/java_src/src/test/java/com/google/crypto/tink/daead/AesSivKeyManagerTest.java b/java_src/src/test/java/com/google/crypto/tink/daead/AesSivKeyManagerTest.java
index cdbedbf..5263cd5 100644
--- a/java_src/src/test/java/com/google/crypto/tink/daead/AesSivKeyManagerTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/daead/AesSivKeyManagerTest.java
@@ -21,6 +21,7 @@
import com.google.crypto.tink.DeterministicAead;
import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeyTypeManager;
import com.google.crypto.tink.proto.AesSivKey;
import com.google.crypto.tink.proto.AesSivKeyFormat;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
@@ -130,7 +131,7 @@
public void createKey_multipleCallsCreateDifferentKeys() throws Exception {
AesSivKeyFormat format = createAesSivKeyFormat(64);
TreeSet<String> keys = new TreeSet<>();
- AesSivKeyManager.KeyFactory<AesSivKeyFormat, AesSivKey> factory =
+ KeyTypeManager.KeyFactory<AesSivKeyFormat, AesSivKey> factory =
new AesSivKeyManager().keyFactory();
final int numKeys = 1000;
for (int i = 0; i < numKeys; ++i) {
diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesAeadHkdfHybridDecryptTest.java b/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesAeadHkdfHybridDecryptTest.java
index d9bb7bf..d5ff72e 100644
--- a/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesAeadHkdfHybridDecryptTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/EciesAeadHkdfHybridDecryptTest.java
@@ -17,7 +17,7 @@
package com.google.crypto.tink.hybrid;
import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
import com.google.crypto.tink.Config;
import com.google.crypto.tink.HybridDecrypt;
@@ -29,7 +29,6 @@
import com.google.crypto.tink.subtle.EciesAeadHkdfHybridEncrypt;
import com.google.crypto.tink.subtle.EllipticCurves;
import com.google.crypto.tink.subtle.EllipticCurves.CurveType;
-import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil;
import com.google.crypto.tink.testing.TestUtil.BytesMutation;
@@ -51,14 +50,15 @@
Config.register(HybridConfig.TINK_1_0_0);
}
- private void testModifyDecrypt(CurveType curveType, KeyTemplate keyTemplate) throws Exception {
+ private static void testEncryptDecrypt(CurveType curveType, KeyTemplate keyTemplate)
+ throws Exception {
KeyPair recipientKey = EllipticCurves.generateKeyPair(curveType);
ECPublicKey recipientPublicKey = (ECPublicKey) recipientKey.getPublic();
ECPrivateKey recipientPrivateKey = (ECPrivateKey) recipientKey.getPrivate();
byte[] salt = Random.randBytes(8);
+ String hmacAlgo = HybridUtil.toHmacAlgo(HashType.SHA256);
byte[] plaintext = Random.randBytes(4);
byte[] context = Random.randBytes(4);
- String hmacAlgo = HybridUtil.toHmacAlgo(HashType.SHA256);
HybridEncrypt hybridEncrypt =
new EciesAeadHkdfHybridEncrypt(
recipientPublicKey,
@@ -75,70 +75,241 @@
new RegistryEciesAeadHkdfDemHelper(keyTemplate));
byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
byte[] decrypted = hybridDecrypt.decrypt(ciphertext, context);
-
assertArrayEquals(plaintext, decrypted);
+ }
- // Modifies ciphertext and makes sure that the decryption failed. This test implicitly checks
- // the modification of public key and the raw ciphertext.
+ @Test
+ public void testEncryptDecryptP256CtrHmac() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P256, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP384CtrHmac() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P384, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP521CtrHmac() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P521, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP256Gcm() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P256, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP384Gcm() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P384, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP512Gcm() throws Exception {
+ testEncryptDecrypt(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
+ }
+
+ private static void testEncryptDecrypt_mutatedCiphertext_throws(
+ CurveType curveType, KeyTemplate keyTemplate) throws Exception {
+ KeyPair recipientKey = EllipticCurves.generateKeyPair(curveType);
+ ECPublicKey recipientPublicKey = (ECPublicKey) recipientKey.getPublic();
+ ECPrivateKey recipientPrivateKey = (ECPrivateKey) recipientKey.getPrivate();
+ byte[] salt = Random.randBytes(8);
+ String hmacAlgo = HybridUtil.toHmacAlgo(HashType.SHA256);
+ byte[] plaintext = Random.randBytes(4);
+ byte[] context = Random.randBytes(4);
+ HybridEncrypt hybridEncrypt =
+ new EciesAeadHkdfHybridEncrypt(
+ recipientPublicKey,
+ salt,
+ hmacAlgo,
+ EllipticCurves.PointFormatType.UNCOMPRESSED,
+ new RegistryEciesAeadHkdfDemHelper(keyTemplate));
+ HybridDecrypt hybridDecrypt =
+ new EciesAeadHkdfHybridDecrypt(
+ recipientPrivateKey,
+ salt,
+ hmacAlgo,
+ EllipticCurves.PointFormatType.UNCOMPRESSED,
+ new RegistryEciesAeadHkdfDemHelper(keyTemplate));
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
for (BytesMutation mutation : TestUtil.generateMutations(ciphertext)) {
- try {
- hybridDecrypt.decrypt(mutation.value, context);
- fail(
- String.format(
- "Invalid ciphertext, should have thrown exception: ciphertext = %s,context = %s,"
- + " description = %s",
- Hex.encode(mutation.value), Hex.encode(context), mutation.description));
- } catch (GeneralSecurityException expected) {
- // Expected
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(mutation.value, context));
+ // The test takes too long in TSan, so we stop after the first case.
+ if (TestUtil.isTsan()) {
+ return;
}
}
+ }
- // Modify context.
+ @Test
+ public void testEncryptDecryptP256CtrHmac_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(
+ CurveType.NIST_P256, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP384CtrHmac_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(
+ CurveType.NIST_P384, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP521CtrHmac_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(
+ CurveType.NIST_P521, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP256Gcm_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(CurveType.NIST_P256, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP384Gcm_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(CurveType.NIST_P384, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP512Gcm_mutatedCiphertext_throws() throws Exception {
+ testEncryptDecrypt_mutatedCiphertext_throws(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
+ }
+
+ private static void testEncryptDecrypt_mutatedContext_throws(
+ CurveType curveType, KeyTemplate keyTemplate) throws Exception {
+ KeyPair recipientKey = EllipticCurves.generateKeyPair(curveType);
+ ECPublicKey recipientPublicKey = (ECPublicKey) recipientKey.getPublic();
+ ECPrivateKey recipientPrivateKey = (ECPrivateKey) recipientKey.getPrivate();
+ byte[] salt = Random.randBytes(8);
+ String hmacAlgo = HybridUtil.toHmacAlgo(HashType.SHA256);
+ byte[] plaintext = Random.randBytes(4);
+ byte[] context = Random.randBytes(4);
+ HybridEncrypt hybridEncrypt =
+ new EciesAeadHkdfHybridEncrypt(
+ recipientPublicKey,
+ salt,
+ hmacAlgo,
+ EllipticCurves.PointFormatType.UNCOMPRESSED,
+ new RegistryEciesAeadHkdfDemHelper(keyTemplate));
+ HybridDecrypt hybridDecrypt =
+ new EciesAeadHkdfHybridDecrypt(
+ recipientPrivateKey,
+ salt,
+ hmacAlgo,
+ EllipticCurves.PointFormatType.UNCOMPRESSED,
+ new RegistryEciesAeadHkdfDemHelper(keyTemplate));
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
for (BytesMutation mutation : TestUtil.generateMutations(context)) {
- try {
- hybridDecrypt.decrypt(ciphertext, mutation.value);
- fail(
- String.format(
- "Invalid context, should have thrown exception: context = %s, ciphertext = %s,"
- + " description = %s",
- Hex.encode(mutation.value), Hex.encode(ciphertext), mutation.description));
- } catch (GeneralSecurityException expected) {
- // Expected
+ // The test takes too long in TSan, so we stop after the first case.
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(ciphertext, mutation.value));
+ if (TestUtil.isTsan()) {
+ return;
}
}
+ }
- // Modify salt.
- // We exclude tests that modify the length of the salt, since the salt has fixed length and
- // modifying the length may not be detected.
+ @Test
+ public void testEncryptDecryptP256CtrHmac_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(
+ CurveType.NIST_P256, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP384CtrHmac_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(
+ CurveType.NIST_P384, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP521CtrHmac_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP256Gcm_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(CurveType.NIST_P256, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP384Gcm_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(CurveType.NIST_P384, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP512Gcm_mutatedContext_throws() throws Exception {
+ testEncryptDecrypt_mutatedContext_throws(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
+ }
+
+ private static void testEncryptDecrypt_mutatedSalt_throws(
+ CurveType curveType, KeyTemplate keyTemplate) throws Exception {
+ KeyPair recipientKey = EllipticCurves.generateKeyPair(curveType);
+ ECPublicKey recipientPublicKey = (ECPublicKey) recipientKey.getPublic();
+ ECPrivateKey recipientPrivateKey = (ECPrivateKey) recipientKey.getPrivate();
+ byte[] salt = Random.randBytes(8);
+ String hmacAlgo = HybridUtil.toHmacAlgo(HashType.SHA256);
+ byte[] plaintext = Random.randBytes(4);
+ byte[] context = Random.randBytes(4);
+ HybridEncrypt hybridEncrypt =
+ new EciesAeadHkdfHybridEncrypt(
+ recipientPublicKey,
+ salt,
+ hmacAlgo,
+ EllipticCurves.PointFormatType.UNCOMPRESSED,
+ new RegistryEciesAeadHkdfDemHelper(keyTemplate));
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
+
for (int bytes = 0; bytes < salt.length; bytes++) {
for (int bit = 0; bit < 8; bit++) {
byte[] modifiedSalt = Arrays.copyOf(salt, salt.length);
modifiedSalt[bytes] ^= (byte) (1 << bit);
- hybridDecrypt =
+ HybridDecrypt hybridDecrypt =
new EciesAeadHkdfHybridDecrypt(
recipientPrivateKey,
modifiedSalt,
hmacAlgo,
EllipticCurves.PointFormatType.UNCOMPRESSED,
new RegistryEciesAeadHkdfDemHelper(keyTemplate));
- try {
- hybridDecrypt.decrypt(ciphertext, context);
- fail("Invalid salt, should have thrown exception");
- } catch (GeneralSecurityException expected) {
- // Expected
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(ciphertext, modifiedSalt));
+ // The test takes too long in TSan, so we stop after the first case.
+ if (TestUtil.isTsan()) {
+ return;
}
}
}
}
@Test
- public void testModifyDecrypt() throws Exception {
- testModifyDecrypt(CurveType.NIST_P256, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
- testModifyDecrypt(CurveType.NIST_P384, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
- testModifyDecrypt(CurveType.NIST_P521, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ public void testEncryptDecryptP256CtrHmac_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(
+ CurveType.NIST_P256, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
- testModifyDecrypt(CurveType.NIST_P256, AeadKeyTemplates.AES128_GCM);
- testModifyDecrypt(CurveType.NIST_P384, AeadKeyTemplates.AES128_GCM);
- testModifyDecrypt(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
+ @Test
+ public void testEncryptDecryptP384CtrHmac_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(
+ CurveType.NIST_P384, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP521CtrHmac_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(
+ CurveType.NIST_P521, AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
+ }
+
+ @Test
+ public void testEncryptDecryptP256Gcm_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(CurveType.NIST_P256, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP384Gcm_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(CurveType.NIST_P384, AeadKeyTemplates.AES128_GCM);
+ }
+
+ @Test
+ public void testEncryptDecryptP512Gcm_mutatedSalt_throws() throws Exception {
+ testEncryptDecrypt_mutatedSalt_throws(CurveType.NIST_P521, AeadKeyTemplates.AES128_GCM);
}
}
diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecryptTest.java b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecryptTest.java
new file mode 100644
index 0000000..3c5db74
--- /dev/null
+++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridDecryptTest.java
@@ -0,0 +1,364 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import com.google.crypto.tink.HybridDecrypt;
+import com.google.crypto.tink.HybridEncrypt;
+import com.google.crypto.tink.aead.subtle.AesGcmFactory;
+import com.google.crypto.tink.subtle.Hex;
+import com.google.crypto.tink.subtle.Random;
+import com.google.crypto.tink.testing.TestUtil;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for RsaKemHybridDecrypt */
+@RunWith(JUnit4.class)
+public final class RsaKemHybridDecryptTest {
+ @Test
+ public void decrypt_modifiedCiphertext() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(2048);
+ String hmacAlgo = "HMACSHA256";
+ byte[] salt = Random.randBytes(20);
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+ HybridEncrypt hybridEncrypt =
+ new RsaKemHybridEncrypt(rsaPublicKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+ HybridDecrypt hybridDecrypt =
+ new RsaKemHybridDecrypt(rsaPrivateKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ byte[] plaintext = Random.randBytes(20);
+ byte[] context = Random.randBytes(20);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
+
+ // Modifies ciphertext and makes sure that the decryption failed. This test implicitly checks
+ // the modification of public key and the raw ciphertext.
+ for (TestUtil.BytesMutation mutation : TestUtil.generateMutations(ciphertext)) {
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(mutation.value, context));
+ }
+ }
+
+ @Test
+ public void decrypt_modifiedContext() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(2048);
+ String hmacAlgo = "HMACSHA256";
+ byte[] salt = Random.randBytes(20);
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+ HybridEncrypt hybridEncrypt =
+ new RsaKemHybridEncrypt(rsaPublicKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+ HybridDecrypt hybridDecrypt =
+ new RsaKemHybridDecrypt(rsaPrivateKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ byte[] plaintext = Random.randBytes(20);
+ byte[] context = Random.randBytes(20);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
+
+ // Modifies context and makes sure that the decryption failed.
+ for (TestUtil.BytesMutation mutation : TestUtil.generateMutations(context)) {
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(ciphertext, mutation.value));
+ }
+ }
+
+ @Test
+ public void decrypt_modifiedSalt() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(2048);
+ String hmacAlgo = "HMACSHA256";
+ byte[] salt = Random.randBytes(20);
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+ HybridEncrypt hybridEncrypt =
+ new RsaKemHybridEncrypt(rsaPublicKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ byte[] plaintext = Random.randBytes(20);
+ byte[] context = Random.randBytes(20);
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
+
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+ // We exclude tests that modify the length of the salt, since the salt has fixed length and
+ // modifying the length may not be detected.
+ for (int bytes = 0; bytes < salt.length; bytes++) {
+ for (int bit = 0; bit < 8; bit++) {
+ byte[] modifiedSalt = Arrays.copyOf(salt, salt.length);
+ modifiedSalt[bytes] ^= (byte) (1 << bit);
+ HybridDecrypt hybridDecrypt =
+ new RsaKemHybridDecrypt(rsaPrivateKey, hmacAlgo, modifiedSalt, new AesGcmFactory(16));
+ assertThrows(
+ GeneralSecurityException.class, () -> hybridDecrypt.decrypt(ciphertext, context));
+ }
+ }
+ }
+
+ @Test
+ public void constructor_shortKey() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(1024);
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+
+ assertThrows(
+ GeneralSecurityException.class,
+ () ->
+ new RsaKemHybridDecrypt(
+ rsaPrivateKey, "HMACSHA256", new byte[0], new AesGcmFactory(16)));
+ }
+
+ private static class RsaKemHybridTestVector {
+ public RSAPrivateKey privateKey;
+ public String hmacAlgo;
+ public byte[] salt;
+ public byte[] contextInfo;
+ int aesGcmKeySizeInBytes;
+ String plaintext;
+ public byte[] ciphertext;
+
+ public RsaKemHybridTestVector(
+ String privateKey,
+ String hmacAlgo,
+ String salt,
+ String contextInfo,
+ int aesGcmKeySizeInBytes,
+ String plaintext,
+ String ciphertext) {
+ try {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Hex.decode(privateKey));
+ this.privateKey = (RSAPrivateKey) kf.generatePrivate(privateKeySpec);
+ this.hmacAlgo = hmacAlgo;
+ this.salt = Hex.decode(salt);
+ this.contextInfo = Hex.decode(contextInfo);
+ this.aesGcmKeySizeInBytes = aesGcmKeySizeInBytes;
+ this.plaintext = plaintext;
+ this.ciphertext = Hex.decode(ciphertext);
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+ }
+
+ // I can't find any public test vector.
+ private static final RsaKemHybridTestVector[] rsaKemHybridTestVectors = {
+ // These are generated by this very implementation, as a mean to verify implementations in other
+ // languages.
+ new RsaKemHybridTestVector(
+ "308204bc020100300d06092a864886f70d0101010500048204a6308204a20201000282010100a071550bcf139d"
+ + "2629d6e6612697f23a0a1abbae78658801f146d846c59141c280b8e361251701d2761ef97d5c38756bea"
+ + "03dafb12da3e8ba527400b5c7dd823e53e3d6b21ed015e818dfe590033ba24e3d483bcd2f3b7707900b3"
+ + "03a7f076236943ddb553be657ee68f19fa9a1ea7ce81a82b87d11ac69e1b01a8ad7b1107bc2f39b8a13c"
+ + "2f1fc69f657c2e318bec3cb04c8e26813cef9a3a50189e690031399eab70637b7cd6a7f850a39303053f"
+ + "8d16655437080b115e2ce5c6d60568eb6963eb4a8e0887384d1ee889b888effc17a275179c047d533ea6"
+ + "70a7cb3286a9a56dbcb00b26cf410732d656db9e5d94511c35ee38f156a0928b36f3be9f47a371020301"
+ + "00010282010079ff5344c473cc95dd509c23193e86a05d5890878ce2df3562ea94bfd3b0ad0921e9f473"
+ + "c4c926c88aaae8d8cacbdf756c1efc5ed7a9fdcf1f88a5e93dae2f30b43acc66ef0811777419ad62ad85"
+ + "a7b02f5143cecbb528322cc03c5eb64f60f5723079a04c8a4510e66dbfba4f80a9e69bae6d533bcc1964"
+ + "d5724079914f94c9edc29cebcf0bf26c6101ce232c705af830e0a4e2850ccff0fbb632fccf8b02a79c2c"
+ + "6572c88d6990a65227c7a37895f0a0c55907659179c2614db5123bacdb6203775b4ded2661046dbf95e1"
+ + "718e582e8b476ce334256e40c236fe2ce625350cfaa787f8fbf68bc78a6d650cd58319d21afd001ed935"
+ + "28a95c3c329413e5740102818100d32993fc23e8ac07120ad347c22df45e7cc4373424e9ce131d6452fa"
+ + "5d27d5c2f998f713d5d3f5fca03cff5a29876e4884c5403b53f4cdcc08678aadcccfc4805e3255eef4f0"
+ + "d95713ccde584b5a021c3dbb57fe51638bd0e9ec2f22cf69d5cea2e98439203b19f35f14b14e8b7b54c8"
+ + "8dccfc56fa887b827f1b0233933ecbc102818100c282b8047ca42034c3b59f682291a7fe1d366495c4d2"
+ + "b65b81632fd3687c040e81568b0c7e8225e1c5d7e7f63193c1929e826978d37f078b3e36e361d73bb4f0"
+ + "1b76065294f713bbca0a6fa955bf3aae110bebefa9ad0749a68d608cb4dd6341db78c79780e6e9e0c736"
+ + "3a15ef5ef614ce8bfc1f2e91ae5c602fa7dff8d983b10281807c20fbe20345da2249e3dd31589f65004a"
+ + "3d99e9e82d1cbbb5d26cc8ca0c09a794cbebaa584f4251dfec1b7b67e039df1d554a9dd58b99926ffa55"
+ + "d63708878da251da9c1e969a5c8ac22a8e22b5657a2e7bbb8d3f50d236dbdbc015a971a082d8d786a782"
+ + "1fdbf0699b236375b0e934ffce5923d42078e24c4f972ab44afcc102818057636b5178be344a0073a4fe"
+ + "a02958946e837585643c56f99d93f674c0c896f9fd59e876e08f907d72e9a1a996748fcf53afbbbb312a"
+ + "2d357dea23165e20d115df0093ae9e86b332f77ee0d3ef564f02cd5dd1ce8728d9d15926c36df4045307"
+ + "cf96dff54d50715b2fa5494b7993ec7344a8d7c91a9f10fb27abc17c7acd1ec102818012e5237bde4670"
+ + "639136fcf2a8308de2cd952d3256071af387754df91c811c7a63ce8a389689f3e9949580f5f659a60698"
+ + "17b6f5849128c56f7bb391b197cb333a926ce2430989c89a9e5de684015d3f4bb32eeebfc5e74101c33d"
+ + "5fd25917389a7f0577c3ac378e902ea391fca6f523c5b54518ea53e322cf75920560280b63",
+ "HMACSHA256",
+ "a19fd193ad1c247422d3",
+ "416efa391903a2e93dcfeecf7d5353ffc97f9b7d",
+ 16,
+ "8012627431bbe7a54375d1accb467c1f7c82d1d758f50a2feda4d42cfabd",
+ "47c8f7b8d060fe7a6f423c0ee287f5a84a28615403c84d5c113aea0bc9b102e8a77ca7120aba15cea3d7bf13cd"
+ + "47f802c8490e02f3209c37ed278b23d2e4230552c0e32f35ca6854c5b3c26082ce2439f311e684f3850b"
+ + "91e780b7839cef502e69f02688aaa768517cfb88288e710b6093e87ebe250bef08e861d6cc2925767d5e"
+ + "1d9185c5fcc3208bc12281e72155bb7453133b1c78da8962a261e9be0b38a97d6fdc4319d66cf241268c"
+ + "b2aaf9fe5905df60db9e3d690b87a2924fe83904b2a21a420d5beecaa61abc5d9438e370886bb8965214"
+ + "bd3624e1c30e1635c36043730d17e8bd63849cb2fefe036a911c8240fc6c2bc2d71768938a48b87e321a"
+ + "ae063b578bfd88000aa61a85794f4b29b64b8e41216e255fc6221296617a1eb3a66666d610c71fbddfd7"
+ + "2911390b05f50d79d0b43ca30e26be996b"),
+ new RsaKemHybridTestVector(
+ "308204be020100300d06092a864886f70d0101010500048204a8308204a402010002820101009540ff714a59a8"
+ + "d4f567da845a5034263946e9fded30c10adff76ad99b10256778baf65b4a05e3e21314e089efb316d559"
+ + "6382290847ee422204f092e0f79b76a1c22d0921daa754489ccbd6a1c59d5e2e98b02b25e42e9272a77d"
+ + "e716eb4068fc22a86756a67a29f96c6e8f60e972aefd68762d5c91583483bd4875ef85fa6039aae30f1b"
+ + "6b27f33a970b04bb399f0aa1c49fcd1880b98402582275e6a75a4f1045d312187019a485ecd3b4eeb0b6"
+ + "076ab532f6c14664841e9d01b6750985f6ba2438ffa4641403e9991c4e6afac0f8ea71bd9645eff3a22c"
+ + "73f77c2d189faa029f06ed5181589e4daacb566229e4dc55fc7c05f33ad93f39de55a85f50d6d9020301"
+ + "00010282010039cb265e96fcaadc737e58660196a6eada28f47867fd05f311107c2670ddcaae0b58d206"
+ + "3d5e948439014f84f9f52df5451cbc0ce970f8f850b5faf5d4f8ec10fec7f2aa639a884aa1a75d62e9d7"
+ + "5c7d58abb523b013705932de5a693e3daffe370bb08bfb48916b6972ac4906acbec4b5c95a616c43b794"
+ + "f6223849ba8af58ced7eae465f20b517ba91b1bbff2f5ae85810885394a9a1435f363c9b29fece9edec8"
+ + "8764af6a05256773a87bc92bd5a017481bea52398f0b0371db4d659e97527ccf6983d81d746da3964fd3"
+ + "5fed63d4ab9c006055c579706940d9f015c6cd7a0c93c827f026c0ad4a59095417da61d80f07b6bacf91"
+ + "a11b6ac51221a94cef2502818100e873d0c21ff9c5ca8e8bb8b848f6a963c1111b639d7c0bf710344c31"
+ + "318b2282c559f0c874c9462415ca4b15ad89d4f90c69b4cfd3ac4a9e2064f4dde2e9cc44222c944221ea"
+ + "7050c7d0f9f01e716a2e2d8755064dd7b78e9b557a9124671f0087c25bf7ce0490ffc6b4da2460bd9676"
+ + "ab169b97ec31967abd2b243378d678bb02818100a45f98c819c4298d2928ed23f97efdd8a439c5d741c4"
+ + "7827ca39e93d58eadca31c213ca715cf1c8b321d3010f55afc2c4f620c1ab341412a2c0caa2f1af9e57d"
+ + "0168267a5401e411cbe24ee114a6eb4b815708ea74b3b78b07d49f639641f55997efdb8e1eb1475f2513"
+ + "23c64e3a33ec0f3bf8120b111f5e639384ac99e7af7b02818100e6e191ea1ee471a69d2afe505c78530a"
+ + "f7cacc0f876e9c5bcb46869f1dfc7a4cb5447e3a3c75662b9551167ef39d41621508314573935f91ebcf"
+ + "1ac0011003897100224a0571dc19003efae19afb3f619a6b1ef26202ef18c00488f6fcd7481db8ba3daa"
+ + "c680169d567a6f694e85409ba19794f7b2ec15f0d74fb06747908edd0281806f751f2d38438a855c8e92"
+ + "d69cfc5e76c34d257903f08c2536fc33cad47b552709110486abc427afbf48896a4664eeafc11853eada"
+ + "f7f98ef6159464a29f26dcafd2869cd64ffded8f59a270ff46fc2fd3c1479b6b8cdd7d59cef4515bf6d7"
+ + "be6bc74a12417fa64cbee00e970e3e6b2cbb5bc7a7bc775cd4ed227f896646f2f702818100b1c5021466"
+ + "a2fa1a2c3fc686a2595e2f04ac7124c4a9134146f30120029046bd20839074fab913e09fccb8debdba4b"
+ + "68d788a8e2aa10041603b875237569c759c628bb722c3c73d1fd27373344ecae1d7d4ed186fc7adbc84d"
+ + "f87275564fed44f160eceef0b2180152ddd581b483d8d87f7155fec2ca563594d413fb7c4fac99",
+ "HMACSHA256",
+ "",
+ "dbe8324084cef0bd79b1e371573f81a455eba51d",
+ 16,
+ "c1ce9e69a387d0f6bc50e0644528726ad6415708582f42977afd352d5493",
+ "39f8503afcb5ab22ee8787cfbc8fbe0462b2a9449389e1c7a042f80505e5260388ee0cd5c33c6b586475d1b078"
+ + "bd6e50e12c85c5e88fc02fe1604dc1182f9afb7066daf04e34cc02747163acada9ec80da24044b3be84c"
+ + "624acb0a8fc8f1cea11d307eb5ec51aa46c1e79ec6c5afad8bfafa3d26495a7acb2652a914531541e270"
+ + "d82e93c91806fb353b20dc62236a3f949c01849e286a7d0f892247dfcf301d5e107f33d1c9627565aa8e"
+ + "28d9b9cc49fe430d69294813bd87d940b9f8fbf98cb9fe5de09e0c763ea2eb9cae4c678b71ab21d861f9"
+ + "821a7ce9d1453bebc702945862edcb25d9db71ea3abf711a069443602005d8abdf9289b80d1512e356f1"
+ + "f6f5fd5673833a615cacec69814ab293530733fa1aadcf76fe8c10595858f5ef744d509fd972b914bc0e"
+ + "537f44b3e463d3063299637d5604c56b30"),
+ // These are generated by an independent implementation in cr/309235397.
+ new RsaKemHybridTestVector(
+ "30820943020100300d06092a864886f70d01010105000482092d3082092902010002820201009765065f3e44a8"
+ + "1f63a771e53dd3ce7fb50830a82e06853c258a8f3761774083b40c967203439becdd10bc9c40c3a7c408"
+ + "113be9bc845b5a8c943b48b9076245990a480e8a4a6cc2ada41a027194b2f80db2056bc78fbf0cac1560"
+ + "93d3442fd981863d50e668f11c0f33f34d5c2b20753ff800952e5c358b1ab46885021c38ccbed1f31a2c"
+ + "53ec641e2b36ff1c049885fdd0c5d02cb1ba2ddd46751f868b0f4a0f06be76c2d81a7579f60d73486e35"
+ + "c9618ddd20243b1cdc367e3c178d001a139b0c7131b789beb214fff2628a66ce5a3a9cf046f0f41bd259"
+ + "34da45b0f0761dbbf5a5c43aa017f08515e4d9e409d9609778fc9f2ae855f01b99c8c867f9293cc82d6c"
+ + "d24b11466185f5d7ff3d25d9ce41835fa8c8381e2c86a2ad7efb52b97aee0401561b3980eecd5ae37b99"
+ + "768dd40cb7fe327992e84b8b730107bb0f6d983c053701b0abfaa51496ac9069032229f9b0c5e76eb829"
+ + "a5b1ed13f7dbc71abb0ab58b442d499fe15a91a48fea210930fde25193cc5fc6d3221861d70553afbc6d"
+ + "b801b35e1acd11437358a76b20f16999ad3db75a70c92c539932ea91c66713d1242a4ab770f53a05de10"
+ + "a76052a5dd7bacb4ebb8abf764ee5cbf355c5634543c66b96eedeba52dc9b494a4de2b061b6ad5ada7ab"
+ + "60599a2010f910bd42c84560c69f53300d55e417206044a779c82d4dabcd1a48b3abbd46ce7645a29771"
+ + "570203010001028202000a8fc5ae074e0adc85bb3cbadd61555a9b6a82da78bb83b7fa767c1f44f168d2"
+ + "c750c97e12b438c0817b956ce127c5206bdfa7ea5a78715713cf938333454c99c65f6d3f766e52c01215"
+ + "0cab76f904b3416155f77ae8904f7601d7c6f84a1d7c7308c6664a6cafc5615a22731726fb10b2f1be38"
+ + "aa0f4cbcf393fa66ad0b02fb65a487ed1f828b4f40bb8b0ea909b90a3ff6bc96154820d0ea4aec08d2fe"
+ + "0887061d56543aab90ccf9412d1709ca867e120c2f8cfa7a153d579fded955c0d810de1434215fc88041"
+ + "342dd6df0100c30c90623a70f8864f1a91969a539a506c2d0edbc840b4464ee53ca3965f8d0512e12630"
+ + "0e8f9c12b14c1ae0d39d0783de587f8bc6e4ce6ce7f62a579f7de54efada511d4c37362ba28d9a4a95da"
+ + "25891e5f499a3b89c007e18e73e08dc4db23380c564994888a437afb5ece1f1f153053b07c6cb233032d"
+ + "c0033f4305eca759751332b4a499bce738912884c3bd926b1cdc4a5c5bd70b3a1fb4d235050b056d36ac"
+ + "9354834da61cd0b9005c3b216fd3adfd1139593c4bfb91d5cd94c866b4d3fab126f13f06e25b2894cecd"
+ + "192db9220da70ffb47e3745e53e2356e18e10a4faeb788d6574bc202ada02d7392accca1c00c94b36adf"
+ + "53b2dba6e610f367f6c7782d61e2a96f835ef7e9fce6012fb8c73863c88139736216535a43ecec6580b5"
+ + "dda2d0cf69593128e32a62cdcd65e25623810282010100dbd85e276c5cc0f46026b3199cd27581846f69"
+ + "29e4ca796633343e8f69c176498b4fe3993c6f48ff9c4310ef1e24a7a1a7481580d39a0212c4cd066ad5"
+ + "d6e609d57eaffcda723154c6cc2254b7ba135d019f7cc6b044083c55e6e26f42655f3d65803d928d3b56"
+ + "7ec8526f69ac5e526f42b8d4f2c4bdf6176c89a835c55820a06980b1681b2a645aebe1f322106ca265b2"
+ + "4148f15805c2b13432125eb9319e7e36c724262d7b1e2d34fca67759acce9c07a5e6d1c96fb7759e22a8"
+ + "89bf61afc34da81f8348b1b45c7acb8c23557f00fc1ade95989c72fe19fb759244a1c819d49b06ee6855"
+ + "ae44f5bd6727aadc79cb9020e1103eea378fe4b676bc7d47b487b10282010100b04ad789a5f1c180ba6d"
+ + "2a6946e971aa5c57f9d3a3e2843abe7abe67a6e2cb1f0572345c23753e85d83b57825a2af9426435be05"
+ + "41db0a91d1176cc56abdbe62458911732d8838cbc0c921355998189e65269a128cad9be72bc3361b2e0f"
+ + "933591e9079fc27b6bb63acb74c150c8fabe7bb78fc50291152abd1a831c7e2f31e52ffab417e7578eef"
+ + "437d5a207f8263c8030f586f07e72a517f9aa44ecbd3c9a44b2b8890b3f79e2192600dbc471c7d09eee1"
+ + "d79d553aed21163b6ce0f50eaf36da964f687a5349302d1954284549c1360ac160f3b045a4763e23e861"
+ + "62fc4bb983658b7ae494111f3780506e0e736cc929156c6acb715703e7750e037f9dd3870282010100ba"
+ + "4beffd9866415cd4ddf6878dcd0aa66683c2aa2da72698e46b31587655ead707a6fb47af5ede8d3cedd8"
+ + "3bc95f666e26437f755bdaf646d15eac417c544f3ba61f6522f03a347392c30994a0dc9dec02a414288a"
+ + "d61be48526d25b55f8716ca5c6b666aa27ce74416d19dc82a4ab567d4403b075e843d235b7b1435fa7fe"
+ + "7df0e98d6c9b18a1522af19e070fc3ff1a0ea4241be06b814088eaa5867f88fcb617d5495cd0cdb414bb"
+ + "021e4ea53f3b161da508a45dfebd887e2900893a149dccf2d1b5629b077bbfa28f3a81f6c1592449e0b5"
+ + "044e0f6424c0623140d797a9cbf0533f544ac712c8eb67aec5ab6fca80a85c10584042353dab219338d6"
+ + "bab50102820101009a8a9155f665eef694f6dbc5fc46eac0a840eb1dafbe03a2a7965c51eb07477ec33c"
+ + "71501039587ce6a866b73baa0e663808b0b2551fdaad2739bcbd772c2cb863329c5c769ec30342d64e49"
+ + "416846b49c0171f12ee78612e9d730183591abbfbb5027c1d23075a502f7963b5d41422637b81bcd5dc9"
+ + "a75f96f4a5d91578f3e970dcfa8135e918c1004de3f337342b9a8bac291ef4339e72614544225b2626ce"
+ + "e2a2a00e11e5d0f6a7259304e8e5bd6b36c13e4d8b08a4156c32dde87a8acbe86f48730628add82be66d"
+ + "1ccc4ca93239d8c5dae2e534b7ce7bfce85a6ef6b2bf46c37eb955a5c338b563c39e2706e267999f5132"
+ + "7173c30f06192416c709a9030282010056c8258f69c9e0fd3d58536d95fbcb074dbf2b90c8fc7e66c338"
+ + "54c7476d60665204cc67fa1a37cc30427a3d70c759058bcd9cf8528009d4bda6ce2f12320013a3df8238"
+ + "59f70afe736ac0771bfe9afdbf8f531c9904fe4ea072f6726c04f51ab947539106c058bbe7afc9bb6530"
+ + "37cb2591503216958e32a143b2a4bf578b8fc495babe031f4ca4ad0a424997828a4b19883ce165335fb7"
+ + "675db88bc79315cecab0a73c778a5f8bc3ef068eef0e5902bc5d3e5aa0947f5acb5e0376699a5ff50ee8"
+ + "9cca30ac7e855cf17cbccdca0e54ca928c5f35fe12d43aaa21b34009ff90961c07e929eec10d8e22bed4"
+ + "7f44eb45f85f7dd52b811ae4aa23f1beb96714ee",
+ "HMACSHA256",
+ "2a9226902d4a4c91a3a0b566a7de001e",
+ "73696d706c6520617320646f207265206d69",
+ 32,
+ "6162632c2065617379206173203132332e",
+ "3e6060a0c1f06e7475ae58d78510cce4ca84ba64705b6195991106818745db0dde5826e789b11ac9e230ff146f"
+ + "7b8e72ff48a6e92adb23036eee424b2af26f6059d315a963bac676ee7827a9c7ea75b42aef28d06d50a8"
+ + "58cfb0f54d663e2c87134201f5fbf67af80a0b185faf721a894e8d43f401fe882a688a0a91cbdd13409f"
+ + "0deeeb86c170a46134372d206581b0f46faaf1ce8b0c30cef83b7d8296c9af37380c95bffa0a832e97dd"
+ + "9f6d4545539893b342665c795fe75744fb0661a73a853ced4ef472857292b6e27aa5729def89b4d53fb8"
+ + "3f0a2825186b80ceecfdebadb2190e6dde117e41d1f365637edf0ee5872e834908a9dbe1cf06131bd994"
+ + "b26c5306a426dd9d621ab972bf5584b3feadf8ab1b0b95ea32ecb3bcb1a51738cf4aae5abe92f34e874b"
+ + "93f07494fa16ed956d4023f68d8b34418136270417134a3ec5372a6ac7df61b2caeecb5101b390b43964"
+ + "a78006127a4c26b05679ba42fbf206862ad85355c12438c5c7143de914974cda72f0e8b752b9e7d4b8ce"
+ + "d1034038291fc02f30bfa630fb10f4c35d09fc2231adf3594be02f248b2e28dcc7a5382c1129dd86ea58"
+ + "1eb2c5abbe06724e762cae49e069c730bb9dda76df7beb99483e55383ae95fcc90772a7a23f5ee556580"
+ + "35a7d1fd812614e6e688039150e8af6afff12e9a8503d530dd1cec8d25b81a59b3a0ba0d7d2e48179bb3"
+ + "756256829f93bf1804641f5d620810037843f17e4009c30957ef91406b1daffd68275e6856903896cfc7"
+ + "749db8814299904a")
+ };
+
+ @Test
+ public void decryptWithTestVectors() throws GeneralSecurityException {
+ for (RsaKemHybridTestVector vector : rsaKemHybridTestVectors) {
+ String hmacAlgo = vector.hmacAlgo;
+ byte[] salt = vector.salt;
+ RSAPrivateKey rsaPrivateKey = vector.privateKey;
+ HybridDecrypt hybridDecrypt =
+ new RsaKemHybridDecrypt(
+ rsaPrivateKey, hmacAlgo, salt, new AesGcmFactory(vector.aesGcmKeySizeInBytes));
+ byte[] plaintext = hybridDecrypt.decrypt(vector.ciphertext, vector.contextInfo);
+ assertThat(Hex.encode(plaintext)).isEqualTo(vector.plaintext);
+ }
+ }
+}
diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncryptTest.java b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncryptTest.java
new file mode 100644
index 0000000..ae7aaeb
--- /dev/null
+++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemHybridEncryptTest.java
@@ -0,0 +1,92 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertThrows;
+
+import com.google.crypto.tink.HybridDecrypt;
+import com.google.crypto.tink.HybridEncrypt;
+import com.google.crypto.tink.aead.subtle.AesGcmFactory;
+import com.google.crypto.tink.subtle.Random;
+import com.google.crypto.tink.testing.TestUtil;
+import java.nio.charset.Charset;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Set;
+import java.util.TreeSet;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for RsaKemHybridEncrypt */
+@RunWith(JUnit4.class)
+public final class RsaKemHybridEncryptTest {
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ @Test
+ public void encrypt_decrypt_success() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(2048);
+ String hmacAlgo = "HMACSHA256";
+ byte[] salt = Random.randBytes(20);
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+ HybridEncrypt hybridEncrypt =
+ new RsaKemHybridEncrypt(rsaPublicKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+ HybridDecrypt hybridDecrypt =
+ new RsaKemHybridDecrypt(rsaPrivateKey, hmacAlgo, salt, new AesGcmFactory(16));
+
+ byte[] plaintext = Random.randBytes(20);
+ byte[] context = Random.randBytes(20);
+
+ // Makes sure that the encryption is randomized.
+ Set<String> ciphertexts = new TreeSet<>();
+ for (int j = 0; j < 8; j++) {
+ byte[] ciphertext = hybridEncrypt.encrypt(plaintext, context);
+ if (ciphertexts.contains(new String(ciphertext, UTF_8))) {
+ throw new GeneralSecurityException("Encryption is not randomized");
+ }
+ ciphertexts.add(new String(ciphertext, UTF_8));
+ byte[] decrypted = hybridDecrypt.decrypt(ciphertext, context);
+ assertArrayEquals(plaintext, decrypted);
+ }
+ assertThat(ciphertexts).hasSize(8);
+ }
+
+ @Test
+ public void constructor_shortKey() throws GeneralSecurityException {
+ if (TestUtil.isTsan()) {
+ // RsaKem.generateRsaKeyPair is too slow in Tsan.
+ return;
+ }
+ KeyPair keyPair = RsaKem.generateRsaKeyPair(1024);
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+
+ assertThrows(
+ GeneralSecurityException.class,
+ () ->
+ new RsaKemHybridEncrypt(
+ rsaPublicKey, "HMACSHA256", new byte[0], new AesGcmFactory(16)));
+ }
+}
diff --git a/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemTest.java b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemTest.java
new file mode 100644
index 0000000..285ad1f
--- /dev/null
+++ b/java_src/src/test/java/com/google/crypto/tink/hybrid/subtle/RsaKemTest.java
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.hybrid.subtle;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for RsaKem * */
+@RunWith(JUnit4.class)
+public final class RsaKemTest {
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ @Test
+ public void bigIntToByteArray_approximate() throws Exception {
+ int expectedSize = 2048;
+ BigInteger bigInt = new BigInteger(2048, new Random());
+ byte[] bigIntBytes = RsaKem.bigIntToByteArray(bigInt, expectedSize);
+
+ assertThat(bigIntBytes).hasLength(expectedSize);
+ assertThat(new BigInteger(1, bigIntBytes)).isEqualTo(bigInt);
+ }
+
+ @Test
+ public void bigIntToByteArray_withALeadingZero() throws Exception {
+ int expectedSize = 2048;
+ BigInteger bigIntWithALeadingZero;
+ while (true) {
+ bigIntWithALeadingZero = new BigInteger(2048, new Random());
+ byte[] r = bigIntWithALeadingZero.toByteArray();
+ if (r[0] == 0) {
+ break;
+ }
+ }
+
+ byte[] modBytes = RsaKem.bigIntToByteArray(bigIntWithALeadingZero, expectedSize);
+ assertThat(modBytes).hasLength(expectedSize);
+ assertThat(new BigInteger(1, modBytes)).isEqualTo(bigIntWithALeadingZero);
+ }
+
+ @Test
+ public void bigIntToByteArray_small() throws Exception {
+ int expectedSize = 2048;
+ BigInteger smallInt = BigInteger.valueOf(42L);
+ byte[] smallIntBytes = RsaKem.bigIntToByteArray(smallInt, expectedSize);
+
+ assertThat(smallIntBytes).hasLength(expectedSize);
+ assertThat(new BigInteger(1, smallIntBytes)).isEqualTo(smallInt);
+ }
+
+ @Test
+ public void generateSecret() throws Exception {
+ BigInteger max = new BigInteger(2048, new Random());
+ int maxSizeInBytes = RsaKem.bigIntSizeInBytes(max);
+
+ Set<String> secrets = new TreeSet<>();
+ for (int i = 0; i < 100; i++) {
+ byte[] secret = RsaKem.generateSecret(max);
+ BigInteger secretBigInt = new BigInteger(1, secret);
+ secrets.add(new String(secret, UTF_8));
+
+ assertThat(secret).hasLength(maxSizeInBytes);
+ assertThat(secretBigInt.signum()).isEqualTo(1);
+ assertThat(secretBigInt.compareTo(max)).isLessThan(0);
+ }
+ assertThat(secrets).hasSize(100);
+ }
+}
diff --git a/java_src/src/test/java/com/google/crypto/tink/mac/HmacKeyManagerTest.java b/java_src/src/test/java/com/google/crypto/tink/mac/HmacKeyManagerTest.java
index a5ea1b9..e5b06a2 100644
--- a/java_src/src/test/java/com/google/crypto/tink/mac/HmacKeyManagerTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/mac/HmacKeyManagerTest.java
@@ -27,7 +27,8 @@
import com.google.crypto.tink.proto.HmacKey;
import com.google.crypto.tink.proto.HmacKeyFormat;
import com.google.crypto.tink.proto.HmacParams;
-import com.google.crypto.tink.subtle.MacJce;
+import com.google.crypto.tink.subtle.PrfHmacJce;
+import com.google.crypto.tink.subtle.PrfMac;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil;
import com.google.protobuf.ByteString;
@@ -234,8 +235,10 @@
HmacKey validKey = factory.createKey(makeHmacKeyFormat(16, 19, HashType.SHA1));
Mac managerMac = manager.getPrimitive(validKey, Mac.class);
Mac directMac =
- new MacJce(
- "HMACSHA1", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC"), 19);
+ new PrfMac(
+ new PrfHmacJce(
+ "HMACSHA1", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC")),
+ 19);
byte[] message = Random.randBytes(50);
managerMac.verifyMac(directMac.computeMac(message), message);
}
@@ -245,8 +248,10 @@
HmacKey validKey = factory.createKey(makeHmacKeyFormat(16, 29, HashType.SHA256));
Mac managerMac = manager.getPrimitive(validKey, Mac.class);
Mac directMac =
- new MacJce(
- "HMACSHA256", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC"), 29);
+ new PrfMac(
+ new PrfHmacJce(
+ "HMACSHA256", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC")),
+ 29);
byte[] message = Random.randBytes(50);
managerMac.verifyMac(directMac.computeMac(message), message);
}
@@ -256,8 +261,10 @@
HmacKey validKey = factory.createKey(makeHmacKeyFormat(16, 33, HashType.SHA512));
Mac managerMac = manager.getPrimitive(validKey, Mac.class);
Mac directMac =
- new MacJce(
- "HMACSHA512", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC"), 33);
+ new PrfMac(
+ new PrfHmacJce(
+ "HMACSHA512", new SecretKeySpec(validKey.getKeyValue().toByteArray(), "HMAC")),
+ 33);
byte[] message = Random.randBytes(50);
managerMac.verifyMac(directMac.computeMac(message), message);
}
diff --git a/java_src/src/test/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManagerTest.java b/java_src/src/test/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManagerTest.java
index 9d1ab1d..cc036fb 100644
--- a/java_src/src/test/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManagerTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/signature/RsaSsaPssSignKeyManagerTest.java
@@ -168,6 +168,18 @@
}
}
+ @Test
+ public void validateKeyFormat_negativeSaltLength_throws() throws Exception {
+ RsaSsaPssKeyFormat format =
+ createKeyFormat(HashType.SHA512, HashType.SHA512, -5, 3072, RSAKeyGenParameterSpec.F4);
+ try {
+ factory.validateKeyFormat(format);
+ fail();
+ } catch (GeneralSecurityException e) {
+ // expected
+ }
+ }
+
private static void checkConsistency(RsaSsaPssPrivateKey privateKey,
RsaSsaPssKeyFormat keyFormat) {
assertThat(privateKey.getPublicKey().getParams()).isEqualTo(keyFormat.getParams());
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/AeadThreadSafetyTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/AeadThreadSafetyTest.java
index 481803f..abf4d61 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/AeadThreadSafetyTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/AeadThreadSafetyTest.java
@@ -150,7 +150,7 @@
int macSize = 12;
IndCpaCipher cipher = new AesCtrJceCipher(key, ivSize);
SecretKeySpec keySpec = new SecretKeySpec(macKey, "HMAC");
- Mac mac = new MacJce("HMACSHA256", keySpec, macSize);
+ Mac mac = new PrfMac(new PrfHmacJce("HMACSHA256", keySpec), macSize);
// TODO(b/148134669): Remove the following line.
// There is a potential (but unlikely) race in java.security.Provider. Since AesCtrHmac
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java
index 7491abc..24860ae 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java
@@ -52,6 +52,15 @@
"../wycheproof/testvectors/ecdsa_secp384r1_sha512_test.json", EcdsaEncoding.DER);
testWycheproofVectors(
"../wycheproof/testvectors/ecdsa_secp521r1_sha512_test.json", EcdsaEncoding.DER);
+ testWycheproofVectors(
+ "../wycheproof/testvectors/ecdsa_secp256r1_sha256_p1363_test.json",
+ EcdsaEncoding.IEEE_P1363);
+ testWycheproofVectors(
+ "../wycheproof/testvectors/ecdsa_secp384r1_sha512_p1363_test.json",
+ EcdsaEncoding.IEEE_P1363);
+ testWycheproofVectors(
+ "../wycheproof/testvectors/ecdsa_secp521r1_sha512_p1363_test.json",
+ EcdsaEncoding.IEEE_P1363);
}
private static void testWycheproofVectors(String fileName, EcdsaEncoding encoding)
@@ -141,18 +150,42 @@
}
@Test
- public void testBasic() throws Exception {
+ public void testAgainstJCEInstance256() throws Exception {
testAgainstJceSignatureInstance(EllipticCurves.getNistP256Params(), HashType.SHA256);
+ }
+
+ @Test
+ public void testAgainstJCEInstance384() throws Exception {
testAgainstJceSignatureInstance(EllipticCurves.getNistP384Params(), HashType.SHA512);
+ }
+
+ @Test
+ public void testAgainstJCEInstance512() throws Exception {
testAgainstJceSignatureInstance(EllipticCurves.getNistP521Params(), HashType.SHA512);
+ }
+
+ @Test
+ public void testSignVerify256() throws Exception {
testSignVerify(EllipticCurves.getNistP256Params(), HashType.SHA256);
+ }
+
+ @Test
+ public void testSignVerify384() throws Exception {
testSignVerify(EllipticCurves.getNistP384Params(), HashType.SHA512);
+ }
+
+ @Test
+ public void testSignVerify512() throws Exception {
testSignVerify(EllipticCurves.getNistP521Params(), HashType.SHA512);
}
private static void testAgainstJceSignatureInstance(ECParameterSpec ecParams, HashType hash)
throws Exception {
- for (int i = 0; i < 100; i++) {
+ int numSignatures = 100;
+ if (TestUtil.isTsan()) {
+ numSignatures = 5;
+ }
+ for (int i = 0; i < numSignatures; i++) {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(ecParams);
KeyPair keyPair = keyGen.generateKeyPair();
@@ -173,7 +206,11 @@
}
private static void testSignVerify(ECParameterSpec ecParams, HashType hash) throws Exception {
- for (int i = 0; i < 100; i++) {
+ int numSignatures = 100;
+ if (TestUtil.isTsan()) {
+ numSignatures = 5;
+ }
+ for (int i = 0; i < numSignatures; i++) {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(ecParams);
KeyPair keyPair = keyGen.generateKeyPair();
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/EllipticCurvesTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/EllipticCurvesTest.java
index 8e39bea..59bff92 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/EllipticCurvesTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/EllipticCurvesTest.java
@@ -549,6 +549,10 @@
@Test
public void testComputeSharedSecretWithWycheproofTestVectors() throws Exception {
+ if (TestUtil.isTsan()) {
+ return;
+ }
+
// NOTE(bleichen): Instead of ecdh_test.json it might be easier to use the
// files ecdh_<curve>_ecpoint.json, which encode the public key point just as DER
// encoded bitsequence.
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/HkdfTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/HkdfTest.java
index 856f3cc..b28465e 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/HkdfTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/HkdfTest.java
@@ -133,6 +133,9 @@
+ "673a081d70cce7acfc48",
computeHkdfHex("HmacSha1", "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", "", "", 42));
}
+
+
+
/**
* Test version of Hkdf where all inputs and outputs are hexadecimal.
*/
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/MacJceTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/PrfHmacJceTest.java
similarity index 66%
rename from java_src/src/test/java/com/google/crypto/tink/subtle/MacJceTest.java
rename to java_src/src/test/java/com/google/crypto/tink/subtle/PrfHmacJceTest.java
index 724e25e..894cd0c 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/MacJceTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/PrfHmacJceTest.java
@@ -17,9 +17,12 @@
package com.google.crypto.tink.subtle;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import com.google.crypto.tink.Mac;
+import com.google.crypto.tink.prf.Prf;
+import com.google.crypto.tink.util.TestUtil;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.util.Arrays;
@@ -28,9 +31,12 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/** Unit tests for MacJce. */
+/**
+ * Unit tests for PrfHmacJce. Note that this used to be a Mac primitive, so all these tests first
+ * convert the Prf to a Mac.
+ */
@RunWith(JUnit4.class)
-public class MacJceTest {
+public class PrfHmacJceTest {
private static class MacTestVector {
String algName;
public byte[] key;
@@ -75,7 +81,8 @@
@Test
public void testMacTestVectors() throws Exception {
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(t.algName, new SecretKeySpec(t.key, "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC")), t.tag.length);
assertArrayEquals(t.tag, mac.computeMac(t.message));
try {
mac.verifyMac(t.tag, t.message);
@@ -86,9 +93,37 @@
}
@Test
+ public void testPrfUniformity() throws GeneralSecurityException {
+ for (MacTestVector t : HMAC_TEST_VECTORS) {
+ Prf prf = new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC"));
+ // We need a string of bytes identical in size to the tag output size for the given algorithm
+ // so we can test cross correlation. We're not actually validating the output contents of the
+ // HMAC in this function. Therefore - just feed the test tag into the HMAC.
+ byte[] prBytes = prf.compute(t.tag, t.tag.length);
+ TestUtil.ztestUniformString(prBytes);
+ TestUtil.ztestAutocorrelationUniformString(prBytes);
+ TestUtil.ztestCrossCorrelationUniformStrings(prBytes, t.tag);
+ }
+ }
+
+ @Test
+ public void testPrfPrefixOfMac() throws Exception {
+ for (MacTestVector t : HMAC_TEST_VECTORS) {
+ Prf prf = new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC"));
+ Mac mac = new PrfMac(prf, t.tag.length);
+ byte[] prBytes = prf.compute(t.message, t.tag.length - 1);
+ byte[] tag = mac.computeMac(t.message);
+
+ assertEquals(prBytes.length, t.tag.length - 1);
+ assertArrayEquals(prBytes, Arrays.copyOf(tag, prBytes.length));
+ }
+ }
+
+ @Test
public void testTagTruncation() throws Exception {
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(t.algName, new SecretKeySpec(t.key, "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC")), t.tag.length);
for (int j = 1; j < t.tag.length; j++) {
byte[] modifiedTag = Arrays.copyOf(t.tag, t.tag.length - j);
try {
@@ -101,8 +136,10 @@
}
// Test with random keys.
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(
- t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(
+ new PrfHmacJce(t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC")),
+ t.tag.length);
for (int j = 1; j < t.tag.length; j++) {
byte[] modifiedTag = Arrays.copyOf(t.tag, t.tag.length - j);
try {
@@ -118,7 +155,8 @@
@Test
public void testBitFlipMessage() throws Exception {
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(t.algName, new SecretKeySpec(t.key, "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC")), t.tag.length);
for (int b = 0; b < t.message.length; b++) {
for (int bit = 0; bit < 8; bit++) {
byte[] modifiedMessage = Arrays.copyOf(t.message, t.message.length);
@@ -134,8 +172,10 @@
}
// Test with random keys.
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(
- t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(
+ new PrfHmacJce(t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC")),
+ t.tag.length);
for (int j = 1; j < t.tag.length; j++) {
byte[] modifiedTag = Arrays.copyOf(t.tag, t.tag.length - j);
try {
@@ -151,7 +191,8 @@
@Test
public void testBitFlipTag() throws Exception {
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(t.algName, new SecretKeySpec(t.key, "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(new PrfHmacJce(t.algName, new SecretKeySpec(t.key, "HMAC")), t.tag.length);
for (int b = 0; b < t.tag.length; b++) {
for (int bit = 0; bit < 8; bit++) {
byte[] modifiedTag = Arrays.copyOf(t.tag, t.tag.length);
@@ -167,8 +208,10 @@
}
// Test with random keys.
for (MacTestVector t : HMAC_TEST_VECTORS) {
- Mac mac = new MacJce(
- t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC"), t.tag.length);
+ Mac mac =
+ new PrfMac(
+ new PrfHmacJce(t.algName, new SecretKeySpec(Random.randBytes(t.key.length), "HMAC")),
+ t.tag.length);
for (int b = 0; b < t.tag.length; b++) {
for (int bit = 0; bit < 8; bit++) {
byte[] modifiedTag = Arrays.copyOf(t.tag, t.tag.length);
@@ -187,7 +230,7 @@
@Test
public void testThrowExceptionIfKeySizeIsTooSmall() throws Exception {
try {
- new MacJce("HMACSHA1", new SecretKeySpec(Random.randBytes(15), "HMAC"), 16);
+ new PrfMac(new PrfHmacJce("HMACSHA1", new SecretKeySpec(Random.randBytes(15), "HMAC")), 16);
fail("Expected InvalidAlgorithmParameterException");
} catch (InvalidAlgorithmParameterException ex) {
// expected.
@@ -201,10 +244,17 @@
testThrowExceptionIfTagSizeIsTooSmall("HMACSHA512");
}
+ @Test
+ public void testPrfAllowsSmallTagSizeCompute() throws Exception {
+ testPrfNoExceptionIfTagSizeIsTooSmall("HMACSHA1");
+ testPrfNoExceptionIfTagSizeIsTooSmall("HMACSHA256");
+ testPrfNoExceptionIfTagSizeIsTooSmall("HMACSHA512");
+ }
+
private static void testThrowExceptionIfTagSizeIsTooSmall(String algoName) throws Exception {
- for (int i = 0; i < MacJce.MIN_TAG_SIZE_IN_BYTES; i++) {
+ for (int i = 0; i < PrfMac.MIN_TAG_SIZE_IN_BYTES; i++) {
try {
- new MacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC"), i);
+ new PrfMac(new PrfHmacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC")), i);
fail("Expected InvalidAlgorithmParameterException");
} catch (InvalidAlgorithmParameterException ex) {
// expected.
@@ -212,17 +262,39 @@
}
}
+ private static void testPrfNoExceptionIfTagSizeIsTooSmall(String algoName) throws Exception {
+ for (int i = 0; i < PrfMac.MIN_TAG_SIZE_IN_BYTES; i++) {
+ new PrfHmacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC"))
+ .compute(new byte[100], i);
+ }
+ }
+
@Test
public void testThrowExceptionIfTagSizeIsTooLarge() throws Exception {
testThrowExceptionIfTagSizeIsTooLarge("HMACSHA1", 21);
testThrowExceptionIfTagSizeIsTooLarge("HMACSHA256", 33);
testThrowExceptionIfTagSizeIsTooLarge("HMACSHA512", 65);
+ testPrfThrowsExceptionIfTagSizeIsTooLarge("HMACSHA1", 21);
+ testPrfThrowsExceptionIfTagSizeIsTooLarge("HMACSHA256", 33);
+ testPrfThrowsExceptionIfTagSizeIsTooLarge("HMACSHA512", 65);
}
private static void testThrowExceptionIfTagSizeIsTooLarge(String algoName, int tagSize)
throws Exception {
try {
- new MacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC"), tagSize);
+ new PrfMac(
+ new PrfHmacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC")), tagSize);
+ fail("Expected InvalidAlgorithmParameterException");
+ } catch (InvalidAlgorithmParameterException ex) {
+ // expected.
+ }
+ }
+
+ public void testPrfThrowsExceptionIfTagSizeIsTooLarge(String algoName, int tagSize)
+ throws Exception {
+ try {
+ Prf r = new PrfHmacJce(algoName, new SecretKeySpec(Random.randBytes(16), "HMAC"));
+ r.compute(new byte[30], tagSize);
fail("Expected InvalidAlgorithmParameterException");
} catch (InvalidAlgorithmParameterException ex) {
// expected.
diff --git a/java_src/src/test/java/com/google/crypto/tink/subtle/prf/HkdfStreamingPrfTest.java b/java_src/src/test/java/com/google/crypto/tink/subtle/prf/HkdfStreamingPrfTest.java
index 655c60e..ef63a13 100644
--- a/java_src/src/test/java/com/google/crypto/tink/subtle/prf/HkdfStreamingPrfTest.java
+++ b/java_src/src/test/java/com/google/crypto/tink/subtle/prf/HkdfStreamingPrfTest.java
@@ -16,10 +16,12 @@
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.crypto.tink.prf.Prf;
import com.google.crypto.tink.subtle.Enums.HashType;
import com.google.crypto.tink.subtle.Hex;
import com.google.crypto.tink.subtle.Hkdf;
import com.google.crypto.tink.subtle.Random;
+import com.google.crypto.tink.util.TestUtil;
import java.io.InputStream;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -308,4 +310,18 @@
assertThat(Hkdf.computeHkdf("HmacSha384", ikm, salt, info, result.length)).isEqualTo(result);
}
+
+ @Test
+ public void testPrfUniformity() throws Exception {
+ for (int i = 0; i < HashType.values().length; i++) {
+ byte[] ikm = Random.randBytes(128);
+ byte[] salt = Random.randBytes(128);
+ byte[] message = Random.randBytes(1024);
+ Prf prf = PrfImpl.wrap(new HkdfStreamingPrf(HashType.SHA256, ikm, salt));
+ byte[] prBytes = prf.compute(message, message.length);
+ TestUtil.ztestUniformString(prBytes);
+ TestUtil.ztestAutocorrelationUniformString(prBytes);
+ TestUtil.ztestCrossCorrelationUniformStrings(prBytes, message);
+ }
+ }
}
diff --git a/java_src/src/test/java/com/google/crypto/tink/util/TestUtilTest.java b/java_src/src/test/java/com/google/crypto/tink/util/TestUtilTest.java
new file mode 100644
index 0000000..8edda06
--- /dev/null
+++ b/java_src/src/test/java/com/google/crypto/tink/util/TestUtilTest.java
@@ -0,0 +1,177 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.util;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests some of the more complex functions from TestUtil. */
+@RunWith(JUnit4.class)
+public class TestUtilTest {
+ SecureRandom random;
+ final byte[] randomBytes = new byte[512];
+ // Correlated to randomBytes: derived by 1 + randomBytes.
+ final byte[] correlatedRandomBytes = new byte[512];
+ final byte[] moreRandomBytes = new byte[512];
+ final ArrayList<Integer> randomIndices = new ArrayList<>(512);
+
+ @Before
+ public void startup() throws NoSuchAlgorithmException {
+ random = SecureRandom.getInstanceStrong();
+ random.setSeed(1234);
+ random.nextBytes(randomBytes);
+ random.nextBytes(moreRandomBytes);
+
+ for (int i = 0; i < randomBytes.length; i++) {
+ correlatedRandomBytes[i] = randomBytes[i];
+ randomIndices.add(i);
+ }
+ Collections.shuffle(randomIndices);
+ }
+
+ @Test
+ public void testZTestUniformitySucceedsOnRandomData() throws GeneralSecurityException {
+ TestUtil.ztestUniformString(randomBytes);
+ }
+
+ @Test
+ public void testZTestUniformityFailsOnNonRandomData() {
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ setValueForNBytes(randomBytes, 256, (byte) 1);
+ TestUtil.ztestUniformString(randomBytes);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Z test for uniformly distributed variable out of bounds");
+ }
+
+ @Test
+ public void testZTestUniformityFailsOnNonRandomNegativeData() {
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ setValueForNBytes(randomBytes, 256, (byte) -120);
+ TestUtil.ztestUniformString(randomBytes);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Z test for uniformly distributed variable out of bounds");
+ }
+
+ @Test
+ public void testZTestUniformityFailsOnSmallUniformMessage() {
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ byte[] allZeros = new byte[16];
+ TestUtil.ztestUniformString(allZeros);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Z test for uniformly distributed variable out of bounds");
+ }
+
+ @Test
+ public void testZTestUniformityFailsWithTooSmallMessage() {
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ byte[] allZeros = new byte[4];
+ TestUtil.ztestUniformString(allZeros);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Use more bytes.");
+ }
+
+ @Test
+ public void testZTestCrossCorrelationUniformitySucceedsOnRandomData()
+ throws GeneralSecurityException {
+ TestUtil.ztestCrossCorrelationUniformStrings(randomBytes, moreRandomBytes);
+ }
+
+ @Test
+ public void testZTestCrossCorrelationUniformityFailsOnCorrelatedData()
+ throws GeneralSecurityException {
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ TestUtil.ztestCrossCorrelationUniformStrings(
+ randomBytes, correlatedRandomBytes);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Z test for uniformly distributed variable out of bounds");
+ }
+
+ @Test
+ public void testZTestAutoCorrelationSucceedsOnRandomData() throws GeneralSecurityException {
+ TestUtil.ztestAutocorrelationUniformString(randomBytes);
+ }
+
+ @Test
+ public void testZTestAutoCorrelationFailsOnAutoCorrelatedData() throws GeneralSecurityException {
+ byte[] repeatedRandom = new byte[randomBytes.length * 3];
+ for (int i = 0; i < 3; i++) {
+ System.arraycopy(randomBytes, 0, repeatedRandom, i * randomBytes.length, randomBytes.length);
+ }
+
+ String msg =
+ assertThrows(
+ GeneralSecurityException.class,
+ new ThrowingRunnable() {
+ @Override
+ public void run() throws Throwable {
+ TestUtil.ztestAutocorrelationUniformString(repeatedRandom);
+ }
+ })
+ .getMessage();
+ assertThat(msg).contains("Z test for uniformly distributed variable out of bounds");
+ }
+
+ private void setValueForNBytes(byte[] input, int numberBytesToSet, byte valueToSet) {
+ for (int i = 0; i < numberBytesToSet; i++) {
+ input[randomIndices.get(i)] = valueToSet;
+ }
+ }
+}
diff --git a/java_src/tink_java_deps_init.bzl b/java_src/tink_java_deps_init.bzl
index 61b7f4a..9c95b78 100644
--- a/java_src/tink_java_deps_init.bzl
+++ b/java_src/tink_java_deps_init.bzl
@@ -43,8 +43,6 @@
)
android_sdk_repository(
name = "androidsdk",
- # Tink uses features in Android Keystore that are only supported at this
- # level or newer.
- # See https://developer.android.com/training/articles/keystore.html.
- api_level = 23, # M
+ # Tink uses some APIs that only supported at this level.
+ api_level = 26, # Oreo
)
diff --git a/java_src/tools/build_defs/tink_java_rules.bzl b/java_src/tools/build_defs/tink_java_rules.bzl
index bf235ef..8487cc8 100644
--- a/java_src/tools/build_defs/tink_java_rules.bzl
+++ b/java_src/tools/build_defs/tink_java_rules.bzl
@@ -1,51 +1,20 @@
"""Tink rules for java."""
-load("//tools/build_defs/android:rules.bzl", "android_binary", "android_instrumentation_test", "android_library")
-load("//devtools/build_cleaner/skylark:build_defs.bzl", "register_extension_info")
+load("//tools/build_defs/android:rules.bzl", "android_binary", "android_instrumentation_test")
-def tink_java_test(name, java_deps = [], android_deps = [], **kwargs):
- """Java Test for Tink.
-
- Creates a java_test for the sources as well as an android_library target, for which
- tests are generated when tink_create_android_test_suite() is called.
-
- This means that tink_create_android_test_suite must be called at some point *after*
- tink_java_test in the BUILD file. Failing to do so is a bug.
- """
-
- native.java_test(name = name, deps = java_deps, **kwargs)
-
- android_library(
- name = name + "_android_test_library",
- deps = android_deps,
- testonly = 1,
- **kwargs
- )
-
-def _is_version_disabled(target, version_num):
- """Returns true if the target should be disabled for this android version.
-
- This is true if target["tags"] exists and contains a string android_min_version:xx"
- with xx > version_num."""
-
- if "tags" not in target:
- return False
- TAG_TO_STRIP = "android_min_version:"
- min_versions = [t[len(TAG_TO_STRIP):] for t in target["tags"] if t.startswith(TAG_TO_STRIP)]
- return any([int(v) > version_num for v in min_versions])
-
-def tink_create_android_test_suite(shard_count = 1):
- """Creates an android test suite for previous tink_java_test.
+def collect_android_libraries_and_make_test_suite(name, shard_count = 1):
+ """Creates an android test suite for android_library in the current package.
Creates, for a bunch of devices, an android_instrumentation_test which
- runs all tests previously defined in tink_java_test, but only for
+ runs all tests previously defined in android_library, but only for
the versions specified there.
- If the tink_java_test target has a tag "android_min_version:xx", the
+ If the android_library target has a tag "android_min_version:xx", the
corresponding test is only added to android versions xx and above.
Args:
- shard_count: the number of shards under which the resulting binary runs.
+ name: The prefix of the generated android test rules.
+ shard_count: the number of shards under which the resulting binary runs.
"""
TARGET_DEVICES = {
@@ -62,33 +31,28 @@
for version_num, device in TARGET_DEVICES.items():
dependencies = {}
for target_name, library_target in native.existing_rules().items():
- if library_target["kind"] == "android_library":
- if not _is_version_disabled(library_target, version_num):
- dependencies[target_name] = True
+ android_min_version = 0
+ if "tags" in library_target:
+ for tag in library_target["tags"]:
+ if tag.startswith("android_min_version"):
+ _, x = tag.split(":")
+ android_min_version = int(x)
+ break
+ if library_target["kind"] == "android_library" and android_min_version <= version_num:
+ dependencies[target_name] = True
dependencies["//java/com/google/android/apps/common/testing/testrunner"] = True
- binary_name = "android_" + str(version_num) + "_collected_binary"
+ binary_name = name + "_" + str(version_num) + "_collected_binary"
android_binary(
name = binary_name,
deps = list(dependencies),
- manifest = "//third_party/tink/javatests:AndroidManifest.xml",
+ manifest = "//third_party/tink/java_src/src/androidtest:AndroidManifest.xml",
testonly = 1,
)
android_instrumentation_test(
- name = "android_test_suite_" + str(version_num) + "_test",
+ name = name + "_" + str(version_num) + "_test",
shard_count = shard_count,
target_device = device,
test_app = binary_name,
+ tags = ["manual"],
)
-
-# Tell build_cleaner that in tink_java_test, java_deps should be the dependencies needed
-# by the created rule with the same name, android_deps should be the dependencies needed
-# by the same name concatenated with _android_test_library.
-# go/build-cleaner-build-extensions
-register_extension_info(
- extension = tink_java_test,
- label_regex_map = {
- "java_deps": "deps:{extension_name}",
- "android_deps": "deps:{extension_name}_android_test_library",
- },
-)
diff --git a/java_src/tools/gen_maven_jar_rules.bzl b/java_src/tools/gen_maven_jar_rules.bzl
index f6b5fbc..fe402bf 100644
--- a/java_src/tools/gen_maven_jar_rules.bzl
+++ b/java_src/tools/gen_maven_jar_rules.bzl
@@ -12,6 +12,7 @@
""" Definition of gen_maven_jar_rules. """
+load("//tools:jar_jar.bzl", "jar_jar")
load("//tools:java_single_jar.bzl", "java_single_jar")
load("//tools:javadoc.bzl", "javadoc_library")
@@ -27,7 +28,10 @@
def gen_maven_jar_rules(
name,
deps = [],
+ resources = [],
root_packages = _TINK_PACKAGES,
+ shaded_packages = [],
+ shading_rules = "",
exclude_packages = [],
doctitle = "",
android_api_level = 23,
@@ -41,7 +45,14 @@
name.jar, a source package name-src.jar and a Javadoc package
name-javadoc.jar.
deps: A combination of the deps of java_single_jar and javadoc_library
+ resources: A list of resource files. Files must be stored in
+ src/main/resources. Mapping rules: src/main/resources/a/b/c.txt will be
+ copied to a/b/c.txt in the output jar.
root_packages: See javadoc_library
+ shaded_packages: These packages will be shaded, according to the rules
+ specified in shading_rules.
+ shading_rules: The shading rules, must specified when shaded_packages is present.
+ Rules file format can be found at https://github.com/bazelbuild/bazel/blob/master/third_party/jarjar/java/com/tonicsystems/jarjar/help.txt.
exclude_packages: See javadoc_library
doctitle: See javadoc_library
android_api_level: See javadoc_library
@@ -49,11 +60,26 @@
external_javadoc_links: See javadoc_library
"""
- java_single_jar(
- name = name,
- deps = deps,
- root_packages = root_packages,
- )
+ if shaded_packages:
+ unshaded_jar = name + "-unshaded"
+ java_single_jar(
+ name = unshaded_jar,
+ deps = deps,
+ resources = resources,
+ root_packages = root_packages + shaded_packages,
+ )
+ jar_jar(
+ name = name,
+ input_jar = unshaded_jar,
+ rules = shading_rules,
+ )
+ else:
+ java_single_jar(
+ name = name,
+ deps = deps,
+ resources = resources,
+ root_packages = root_packages,
+ )
source_jar_name = name + "-src"
java_single_jar(
diff --git a/java_src/tools/jar_jar.bzl b/java_src/tools/jar_jar.bzl
index facc78c..418b8d6 100644
--- a/java_src/tools/jar_jar.bzl
+++ b/java_src/tools/jar_jar.bzl
@@ -9,7 +9,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Skylark rules for jarjar. See https://github.com/pantsbuild/jarjar
+"""starlark rules for jarjar. See https://github.com/pantsbuild/jarjar
"""
def _jar_jar_impl(ctx):
diff --git a/java_src/tools/java_single_jar.bzl b/java_src/tools/java_single_jar.bzl
index ad96577..bc4244d 100644
--- a/java_src/tools/java_single_jar.bzl
+++ b/java_src/tools/java_single_jar.bzl
@@ -20,12 +20,10 @@
_check_non_empty(ctx.attr.root_packages, "root_packages")
inputs = depset()
- source_jars = []
- for dep in ctx.attr.deps:
- inputs = depset(transitive = [inputs, dep[JavaInfo].transitive_runtime_deps])
- source_jars += dep[JavaInfo].transitive_source_jars.to_list()
if ctx.attr.source_jar:
- inputs = depset(direct = source_jars)
+ inputs = depset(transitive = [dep[JavaInfo].transitive_source_jars for dep in ctx.attr.deps])
+ else:
+ inputs = depset(transitive = [dep[JavaInfo].transitive_runtime_deps for dep in ctx.attr.deps])
args = ctx.actions.args()
args.add_all("--sources", inputs)
@@ -37,6 +35,18 @@
args.add("--output", ctx.outputs.jar)
args.add("--normalize")
+ resource_files = depset(
+ transitive = [resource.files for resource in ctx.attr.resources],
+ ).to_list()
+ args.add("--resources")
+ for resource_file in resource_files:
+ if not resource_file.path.startswith("src/main/resources"):
+ fail("resource %s must be stored in src/main/resources/" % resource_file.path)
+ relative_path = resource_file.path.replace("src/main/resources/", "")
+
+ # Map src/main/resources/a/b/c.txt to a/b/c.txt.
+ args.add(resource_file.path, format = "%s:" + relative_path)
+
# Maybe compress code.
if not ctx.attr.source_jar:
# Deal with limitation of singlejar flags: tool's default behavior is
@@ -55,7 +65,7 @@
args.add("--include_prefixes", p.replace(".", "/"))
ctx.actions.run(
- inputs = inputs,
+ inputs = inputs.to_list() + resource_files,
outputs = [ctx.outputs.jar],
arguments = [args],
progress_message = "Merging into %s" % ctx.outputs.jar.short_path,
@@ -66,6 +76,10 @@
java_single_jar = rule(
attrs = {
"deps": attr.label_list(providers = [JavaInfo]),
+ "resources": attr.label_list(
+ providers = [JavaInfo],
+ allow_files = True,
+ ),
"_singlejar": attr.label(
default = Label("@bazel_tools//tools/jdk:singlejar"),
cfg = "host",
@@ -89,6 +103,9 @@
exports) and runtime dependencies (runtime_deps) are collected.
Resources are also collected. Native cc_library or java_wrap_cc
dependencies are not.
+ resources: A combination of resource files. Files must be stored in
+ src/main/resources. Mapping rules: src/main/resources/a/b/c.txt will be
+ copied to a/b/c.txt in the output jar.
compress: Whether to always deflate ("yes"), always store ("no"), or pass
through unmodified ("preserve"). The default is "preserve", and is the
most efficient option -- no extra work is done to inflate or deflate.
diff --git a/java_src/tools/javadoc.bzl b/java_src/tools/javadoc.bzl
index 7ee1293..d456513 100644
--- a/java_src/tools/javadoc.bzl
+++ b/java_src/tools/javadoc.bzl
@@ -10,7 +10,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-""" Definition of javadoc_library. """
+"""
+Generates a Javadoc jar path/to/target/<name>.jar.
+
+Arguments:
+ srcs: source files to process. This might contain .java files or gen_rule that
+ generates source jars.
+ deps: targets that contain references to other types referenced in Javadoc. This can be the
+ java_library/android_library target(s) for the same sources
+ root_packages: Java packages to include in generated Javadoc. Any subpackages not listed in
+ exclude_packages will be included as well
+ exclude_packages: Java packages to exclude from generated Javadoc
+ android_api_level: If Android APIs are used, the API level to compile against to generate
+ Javadoc
+ doctitle: title for Javadoc's index.html. See javadoc -doctitle
+ bottom_text: text passed to javadoc's `-bottom` flag
+ external_javadoc_links: a list of URLs that are passed to Javadoc's `-linkoffline` flag
+"""
def _check_non_empty(value, name):
if not value:
@@ -104,20 +120,3 @@
outputs = {"jar": "%{name}.jar"},
implementation = _javadoc_library,
)
-"""
-Generates a Javadoc jar path/to/target/<name>.jar.
-
-Arguments:
- srcs: source files to process. This might contain .java files or gen_rule that
- generates source jars.
- deps: targets that contain references to other types referenced in Javadoc. This can be the
- java_library/android_library target(s) for the same sources
- root_packages: Java packages to include in generated Javadoc. Any subpackages not listed in
- exclude_packages will be included as well
- exclude_packages: Java packages to exclude from generated Javadoc
- android_api_level: If Android APIs are used, the API level to compile against to generate
- Javadoc
- doctitle: title for Javadoc's index.html. See javadoc -doctitle
- bottom_text: text passed to javadoc's `-bottom` flag
- external_javadoc_links: a list of URLs that are passed to Javadoc's `-linkoffline` flag
-"""
diff --git a/javascript/aead/aead_config_test.js b/javascript/aead/aead_config_test.js
index 22a5d21..6ba4441 100644
--- a/javascript/aead/aead_config_test.js
+++ b/javascript/aead/aead_config_test.js
@@ -20,9 +20,9 @@
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
const AesCtrHmacAeadKeyManager = goog.require('tink.aead.AesCtrHmacAeadKeyManager');
const AesGcmKeyManager = goog.require('tink.aead.AesGcmKeyManager');
-const KeysetHandle = goog.require('tink.KeysetHandle');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const {KeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.keyset_handle');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {PbKeyData, PbKeyStatusType, PbKeyTemplate, PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('aead config test', function() {
diff --git a/javascript/aead/aead_wrapper.js b/javascript/aead/aead_wrapper.js
index 35bfbea..d069766 100644
--- a/javascript/aead/aead_wrapper.js
+++ b/javascript/aead/aead_wrapper.js
@@ -15,10 +15,10 @@
goog.module('tink.aead.AeadWrapper');
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
-const Registry = goog.require('tink.Registry');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbKeyStatusType} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/aead/aead_wrapper_test.js b/javascript/aead/aead_wrapper_test.js
index 77fa276..2401f5d 100644
--- a/javascript/aead/aead_wrapper_test.js
+++ b/javascript/aead/aead_wrapper_test.js
@@ -17,9 +17,9 @@
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
const AeadWrapper = goog.require('tink.aead.AeadWrapper');
-const Bytes = goog.require('tink.subtle.Bytes');
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/aead/aes_ctr_hmac.ts b/javascript/aead/aes_ctr_hmac.ts
index 81365f2..8e6febf 100644
--- a/javascript/aead/aes_ctr_hmac.ts
+++ b/javascript/aead/aes_ctr_hmac.ts
@@ -1,6 +1,6 @@
import AesCtrHmacAeadKeyManager from 'goog:tink.aead.AesCtrHmacAeadKeyManager'; // from //third_party/tink/javascript/aead:aes_ctr_hmac_aead_key_manager
import AesCtrHmacAeadKeyTemplates from 'goog:tink.aead.AesCtrHmacAeadKeyTemplates'; // from //third_party/tink/javascript/aead:aes_ctr_hmac_aead_key_templates
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerKeyManager(new AesCtrHmacAeadKeyManager());
diff --git a/javascript/aead/aes_ctr_hmac_aead_key_manager.js b/javascript/aead/aes_ctr_hmac_aead_key_manager.js
index 968b2fd..7676bc8 100644
--- a/javascript/aead/aes_ctr_hmac_aead_key_manager.js
+++ b/javascript/aead/aes_ctr_hmac_aead_key_manager.js
@@ -15,12 +15,12 @@
goog.module('tink.aead.AesCtrHmacAeadKeyManager');
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const EncryptThenAuthenticate = goog.require('tink.subtle.EncryptThenAuthenticate');
-const KeyManager = goog.require('tink.KeyManager');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const {aesCtrHmacFromRawKeys} = goog.require('google3.third_party.tink.javascript.subtle.encrypt_then_authenticate');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesCtrKey, PbAesCtrKeyFormat, PbHashType, PbHmacKey, PbHmacKeyFormat, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -242,7 +242,7 @@
hashType = 'UNKNOWN HASH';
}
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
aesCtrKey.getKeyValue_asU8(), aesCtrKey.getParams().getIvSize(),
hashType, hmacKey.getKeyValue_asU8(), hmacKey.getParams().getTagSize());
diff --git a/javascript/aead/aes_ctr_hmac_aead_key_manager_test.js b/javascript/aead/aes_ctr_hmac_aead_key_manager_test.js
index ffc0ee5..d2cbff0 100644
--- a/javascript/aead/aes_ctr_hmac_aead_key_manager_test.js
+++ b/javascript/aead/aes_ctr_hmac_aead_key_manager_test.js
@@ -18,7 +18,7 @@
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
const AesCtrHmacAeadKeyManager = goog.require('tink.aead.AesCtrHmacAeadKeyManager');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const Random = goog.require('tink.subtle.Random');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesCtrKey, PbAesCtrKeyFormat, PbAesCtrParams, PbHashType, PbHmacKey, PbHmacKeyFormat, PbHmacParams, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
const KEY_TYPE = 'type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey';
diff --git a/javascript/aead/aes_gcm.ts b/javascript/aead/aes_gcm.ts
index b6afa48..8529933 100644
--- a/javascript/aead/aes_gcm.ts
+++ b/javascript/aead/aes_gcm.ts
@@ -1,6 +1,6 @@
import AesGcmKeyManager from 'goog:tink.aead.AesGcmKeyManager'; // from //third_party/tink/javascript/aead:aes_gcm_key_manager
import AesGcmKeyTemplates from 'goog:tink.aead.AesGcmKeyTemplates'; // from //third_party/tink/javascript/aead:aes_gcm_key_templates
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerKeyManager(new AesGcmKeyManager());
diff --git a/javascript/aead/aes_gcm_key_manager.js b/javascript/aead/aes_gcm_key_manager.js
index eb8c833..1d8c978 100644
--- a/javascript/aead/aes_gcm_key_manager.js
+++ b/javascript/aead/aes_gcm_key_manager.js
@@ -15,12 +15,12 @@
goog.module('tink.aead.AesGcmKeyManager');
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const AesGcm = goog.require('tink.subtle.AesGcm');
-const KeyManager = goog.require('tink.KeyManager');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const aesGcm = goog.require('google3.third_party.tink.javascript.subtle.aes_gcm');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const {PbAesGcmKey, PbAesGcmKeyFormat, PbKeyData, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -126,7 +126,7 @@
const keyProto = AesGcmKeyManager.getKeyProto_(key);
AesGcmKeyManager.validateKey_(keyProto);
- return await AesGcm.newInstance(keyProto.getKeyValue_asU8());
+ return await aesGcm.fromRawKey(keyProto.getKeyValue_asU8());
}
/** @override */
diff --git a/javascript/aead/aes_gcm_key_manager_test.js b/javascript/aead/aes_gcm_key_manager_test.js
index 95e78df..8e332d2 100644
--- a/javascript/aead/aes_gcm_key_manager_test.js
+++ b/javascript/aead/aes_gcm_key_manager_test.js
@@ -18,7 +18,7 @@
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
const AesGcmKeyManager = goog.require('tink.aead.AesGcmKeyManager');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const Random = goog.require('tink.subtle.Random');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbAesCtrKey, PbAesCtrKeyFormat, PbAesGcmKey, PbAesGcmKeyFormat, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
const KEY_TYPE = 'type.googleapis.com/google.crypto.tink.AesGcmKey';
diff --git a/javascript/aead/subtle/aes_ctr_hmac.ts b/javascript/aead/subtle/aes_ctr_hmac.ts
index d78ae72..6e064f3 100644
--- a/javascript/aead/subtle/aes_ctr_hmac.ts
+++ b/javascript/aead/subtle/aes_ctr_hmac.ts
@@ -1,3 +1 @@
-import {EncryptThenAuthenticate} from './encrypt_then_authenticate';
-
-export const aesCtrHmac = EncryptThenAuthenticate.newAesCtrHmac;
+export {aesCtrHmacFromRawKeys as fromRawKeys} from '../../subtle/encrypt_then_authenticate';
diff --git a/javascript/aead/subtle/aes_gcm.ts b/javascript/aead/subtle/aes_gcm.ts
index 268b6a7..d3df615 100644
--- a/javascript/aead/subtle/aes_gcm.ts
+++ b/javascript/aead/subtle/aes_gcm.ts
@@ -1 +1 @@
-export {default as AesGcm} from 'goog:tink.subtle.AesGcm'; // from //third_party/tink/javascript/subtle:aead
+export {AesGcm, fromRawKey} from '../../subtle/aes_gcm';
diff --git a/javascript/aead/subtle/encrypt_then_authenticate.ts b/javascript/aead/subtle/encrypt_then_authenticate.ts
index 5a45f02..13ff598 100644
--- a/javascript/aead/subtle/encrypt_then_authenticate.ts
+++ b/javascript/aead/subtle/encrypt_then_authenticate.ts
@@ -1 +1 @@
-export {default as EncryptThenAuthenticate} from 'goog:tink.subtle.EncryptThenAuthenticate'; // from //third_party/tink/javascript/subtle:aead
+export {EncryptThenAuthenticate} from '../../subtle/encrypt_then_authenticate';
diff --git a/javascript/aead/subtle/index.ts b/javascript/aead/subtle/index.ts
index 618a9d2..8796fc5 100644
--- a/javascript/aead/subtle/index.ts
+++ b/javascript/aead/subtle/index.ts
@@ -1,3 +1,3 @@
-export * from './aes_ctr_hmac';
-export * from './aes_gcm';
+export {fromRawKeys as aesCtrHmac} from './aes_ctr_hmac';
+export {AesGcm, fromRawKey as aesGcmFromRawKey} from './aes_gcm';
export * from './encrypt_then_authenticate';
diff --git a/javascript/aead/wrapper.ts b/javascript/aead/wrapper.ts
index d6382c3..9ac8258 100644
--- a/javascript/aead/wrapper.ts
+++ b/javascript/aead/wrapper.ts
@@ -1,5 +1,5 @@
import AeadWrapper from 'goog:tink.aead.AeadWrapper'; // from //third_party/tink/javascript/aead:aead_wrapper
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerPrimitiveWrapper(new AeadWrapper());
diff --git a/javascript/binary/index.ts b/javascript/binary/index.ts
index 2379b00..4d45e2f 100644
--- a/javascript/binary/index.ts
+++ b/javascript/binary/index.ts
@@ -1,8 +1,7 @@
-import BinaryKeysetReader from 'goog:tink.BinaryKeysetReader'; // from //third_party/tink/javascript:binary_reader
-import KeysetHandle from 'goog:tink.KeysetHandle'; // from //third_party/tink/javascript:keyset_handle_legacy
+import {BinaryKeysetReader} from '../internal/binary_keyset_reader';
+import {KeysetHandle, readNoSecret} from '../internal/keyset_handle';
export function deserializeNoSecretKeyset(
serializedKeyset: Uint8Array): KeysetHandle {
- return KeysetHandle.readNoSecret(
- BinaryKeysetReader.withUint8Array(serializedKeyset));
+ return readNoSecret(BinaryKeysetReader.withUint8Array(serializedKeyset));
}
diff --git a/javascript/binary/insecure/index.ts b/javascript/binary/insecure/index.ts
index fb438de..94a9b65 100644
--- a/javascript/binary/insecure/index.ts
+++ b/javascript/binary/insecure/index.ts
@@ -1,4 +1,4 @@
-import CleartextKeysetHandle from 'goog:tink.CleartextKeysetHandle'; // from //third_party/tink/javascript:cleartext_keyset_handle
+import {CleartextKeysetHandle} from '../../internal/cleartext_keyset_handle';
export const deserializeKeyset = CleartextKeysetHandle.deserializeFromBinary;
export const serializeKeyset = CleartextKeysetHandle.serializeToBinary;
diff --git a/javascript/crypto_format.js b/javascript/crypto_format.js
deleted file mode 100644
index 5c65187..0000000
--- a/javascript/crypto_format.js
+++ /dev/null
@@ -1,136 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.CryptoFormat');
-
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const {PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
-
-/**
- * Constants and methods that deal with the format of the outputs handled by
- * Tink.
- *
- * @static
- * @final
- */
-class CryptoFormat {
- /**
- * Generates the prefix for the outputs handled by the given 'key'.
- * Throws an exception if the prefix type of 'key' is invalid.
- *
- * @param {PbKeyset.Key} key
- *
- * @return {!Uint8Array}
- */
- static getOutputPrefix(key) {
- switch (key.getOutputPrefixType()) {
- case PbOutputPrefixType.LEGACY: // fall through
- case PbOutputPrefixType.CRUNCHY:
- return CryptoFormat.makeOutputPrefix_(
- key.getKeyId(), CryptoFormat.LEGACY_START_BYTE);
- case PbOutputPrefixType.TINK:
- return CryptoFormat.makeOutputPrefix_(
- key.getKeyId(), CryptoFormat.TINK_START_BYTE);
- case PbOutputPrefixType.RAW:
- return CryptoFormat.RAW_PREFIX;
- default:
- throw new SecurityException('Unsupported key prefix type.');
- }
- }
-
- /**
- * Makes output prefix which consits of 4 bytes of key id in Big Endian
- * representation followed by 1 byte of key type identifier.
- *
- * @static
- * @private
- * @param {number} keyId
- * @param {number} keyTypeIdentifier
- *
- * @return {!Uint8Array}
- */
- static makeOutputPrefix_(keyId, keyTypeIdentifier) {
- let /** Array */ res = [keyTypeIdentifier];
- res = res.concat(CryptoFormat.numberAsBigEndian_(keyId));
- return new Uint8Array(res);
- }
-
-
- /**
- * Returns the given number as Uint8Array in Big Endian format.
- *
- * Given number has to be a non-negative integer smaller than 2^32.
- *
- * @static
- * @private
- * @param {number} n
- *
- * @return {!Array}
- */
- static numberAsBigEndian_(n) {
- if (!Number.isInteger(n) || n < 0 || n >= 2**32) {
- throw new InvalidArgumentsException(
- 'Number has to be unsigned 32-bit integer.');
- }
- const numberOfBytes = 4;
- let res = new Array(numberOfBytes);
- for (let i = 0; i < numberOfBytes; i++) {
- res[i] = 0xFF & (n >> 8 * (numberOfBytes - i - 1));
- }
- return res;
- }
-}
-
-/**
- * Prefix size of Tink and Legacy key types.
- * @const @static {number}
- */
-CryptoFormat.NON_RAW_PREFIX_SIZE = 5;
-
-/**
- * Prefix size of Legacy key types.
- * @const @static {number}
- */
-CryptoFormat.LEGACY_PREFIX_SIZE = CryptoFormat.NON_RAW_PREFIX_SIZE;
-/**
- * Legacy starts with 0 and is followed by 4-byte key id.
- * @const @static {number}
- */
-CryptoFormat.LEGACY_START_BYTE = 0x00;
-
-/**
- * Prefix size of Tink key types.
- * @const @static {number}
- */
-CryptoFormat.TINK_PREFIX_SIZE = CryptoFormat.NON_RAW_PREFIX_SIZE;
-/**
- * Tink starts with 1 and is followed by 4-byte key id.
- * @const @static {number}
- */
-CryptoFormat.TINK_START_BYTE = 0x01;
-
-/**
- * Raw prefix should have length 0.
- * @const @static {number}
- */
-CryptoFormat.RAW_PREFIX_SIZE = 0;
-/**
- * Raw prefix is empty Uint8Array.
- * @const @static
- * @type {!Uint8Array}
- */
-CryptoFormat.RAW_PREFIX = new Uint8Array(0);
-
-exports = CryptoFormat;
diff --git a/javascript/hybrid/decrypt_wrapper.ts b/javascript/hybrid/decrypt_wrapper.ts
index 0b7d2c6..597912b 100644
--- a/javascript/hybrid/decrypt_wrapper.ts
+++ b/javascript/hybrid/decrypt_wrapper.ts
@@ -1,5 +1,5 @@
import HybridDecryptWrapper from 'goog:tink.hybrid.HybridDecryptWrapper'; // from //third_party/tink/javascript/hybrid:hybrid_wrappers
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerPrimitiveWrapper(new HybridDecryptWrapper());
diff --git a/javascript/hybrid/ecies_aead_hkdf_for_decrypting.ts b/javascript/hybrid/ecies_aead_hkdf_for_decrypting.ts
index 6964d61..99cdb7c 100644
--- a/javascript/hybrid/ecies_aead_hkdf_for_decrypting.ts
+++ b/javascript/hybrid/ecies_aead_hkdf_for_decrypting.ts
@@ -1,5 +1,5 @@
import EciesAeadHkdfPrivateKeyManager from 'goog:tink.hybrid.EciesAeadHkdfPrivateKeyManager'; // from //third_party/tink/javascript/hybrid:ecies_aead_hkdf_key_managers
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerKeyManager(new EciesAeadHkdfPrivateKeyManager());
diff --git a/javascript/hybrid/ecies_aead_hkdf_for_encrypting.ts b/javascript/hybrid/ecies_aead_hkdf_for_encrypting.ts
index fdb9b04..e38e283 100644
--- a/javascript/hybrid/ecies_aead_hkdf_for_encrypting.ts
+++ b/javascript/hybrid/ecies_aead_hkdf_for_encrypting.ts
@@ -1,5 +1,5 @@
import EciesAeadHkdfPublicKeyManager from 'goog:tink.hybrid.EciesAeadHkdfPublicKeyManager'; // from //third_party/tink/javascript/hybrid:ecies_aead_hkdf_key_managers
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerKeyManager(new EciesAeadHkdfPublicKeyManager());
diff --git a/javascript/hybrid/ecies_aead_hkdf_private_key_manager.js b/javascript/hybrid/ecies_aead_hkdf_private_key_manager.js
index 92e3df8..ca68a58 100644
--- a/javascript/hybrid/ecies_aead_hkdf_private_key_manager.js
+++ b/javascript/hybrid/ecies_aead_hkdf_private_key_manager.js
@@ -14,17 +14,17 @@
goog.module('tink.hybrid.EciesAeadHkdfPrivateKeyManager');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EciesAeadHkdfHybridDecrypt = goog.require('tink.subtle.EciesAeadHkdfHybridDecrypt');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const hybridDecrypt = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_hybrid_decrypt');
const EciesAeadHkdfPublicKeyManager = goog.require('tink.hybrid.EciesAeadHkdfPublicKeyManager');
const EciesAeadHkdfUtil = goog.require('tink.hybrid.EciesAeadHkdfUtil');
const EciesAeadHkdfValidators = goog.require('tink.hybrid.EciesAeadHkdfValidators');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
-const KeyManager = goog.require('tink.KeyManager');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const RegistryEciesAeadHkdfDemHelper = goog.require('tink.hybrid.RegistryEciesAeadHkdfDemHelper');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEciesAeadHkdfKeyFormat, PbEciesAeadHkdfParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbKeyData, PbKeyTemplate, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -204,7 +204,7 @@
Util.hashTypeProtoToString(params.getKemParams().getHkdfHashType());
const hkdfSalt = params.getKemParams().getHkdfSalt_asU8();
- return await EciesAeadHkdfHybridDecrypt.newInstance(
+ return await hybridDecrypt.fromJsonWebKey(
recepientPrivateKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
}
diff --git a/javascript/hybrid/ecies_aead_hkdf_private_key_manager_test.js b/javascript/hybrid/ecies_aead_hkdf_private_key_manager_test.js
index 81e8f53..5541fa6 100644
--- a/javascript/hybrid/ecies_aead_hkdf_private_key_manager_test.js
+++ b/javascript/hybrid/ecies_aead_hkdf_private_key_manager_test.js
@@ -21,9 +21,9 @@
const EciesAeadHkdfPublicKeyManager = goog.require('tink.hybrid.EciesAeadHkdfPublicKeyManager');
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
-const KeyManager = goog.require('tink.KeyManager');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {PbAesCtrKeyFormat, PbEciesAeadDemParams, PbEciesAeadHkdfKeyFormat, PbEciesAeadHkdfParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbEciesHkdfKemParams, PbEllipticCurveType, PbHashType, PbKeyData, PbKeyTemplate, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {assertExists, assertInstanceof} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/hybrid/ecies_aead_hkdf_public_key_manager.js b/javascript/hybrid/ecies_aead_hkdf_public_key_manager.js
index f517fb5..625e3b1 100644
--- a/javascript/hybrid/ecies_aead_hkdf_public_key_manager.js
+++ b/javascript/hybrid/ecies_aead_hkdf_public_key_manager.js
@@ -14,14 +14,14 @@
goog.module('tink.hybrid.EciesAeadHkdfPublicKeyManager');
-const EciesAeadHkdfHybridEncrypt = goog.require('tink.subtle.EciesAeadHkdfHybridEncrypt');
+const encrypt = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_hybrid_encrypt');
const EciesAeadHkdfUtil = goog.require('tink.hybrid.EciesAeadHkdfUtil');
const EciesAeadHkdfValidators = goog.require('tink.hybrid.EciesAeadHkdfValidators');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
-const KeyManager = goog.require('tink.KeyManager');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const RegistryEciesAeadHkdfDemHelper = goog.require('tink.hybrid.RegistryEciesAeadHkdfDemHelper');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEciesAeadHkdfParams, PbEciesAeadHkdfPublicKey, PbKeyData, PbKeyTemplate, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -76,7 +76,7 @@
Util.hashTypeProtoToString(params.getKemParams().getHkdfHashType());
const hkdfSalt = params.getKemParams().getHkdfSalt_asU8();
- return await EciesAeadHkdfHybridEncrypt.newInstance(
+ return await encrypt.fromJsonWebKey(
recepientPublicKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
}
diff --git a/javascript/hybrid/ecies_aead_hkdf_public_key_manager_test.js b/javascript/hybrid/ecies_aead_hkdf_public_key_manager_test.js
index 18fa8fe..36366d8 100644
--- a/javascript/hybrid/ecies_aead_hkdf_public_key_manager_test.js
+++ b/javascript/hybrid/ecies_aead_hkdf_public_key_manager_test.js
@@ -17,14 +17,14 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const EciesAeadHkdfPublicKeyManager = goog.require('tink.hybrid.EciesAeadHkdfPublicKeyManager');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
-const Util = goog.require('tink.Util');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbAesCtrKey, PbEciesAeadDemParams, PbEciesAeadHkdfParams, PbEciesAeadHkdfPublicKey, PbEciesHkdfKemParams, PbEllipticCurveType, PbHashType, PbKeyData, PbKeyTemplate, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {assertExists} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/hybrid/ecies_aead_hkdf_util.js b/javascript/hybrid/ecies_aead_hkdf_util.js
index d273248..5716e34 100644
--- a/javascript/hybrid/ecies_aead_hkdf_util.js
+++ b/javascript/hybrid/ecies_aead_hkdf_util.js
@@ -14,8 +14,8 @@
goog.module('tink.hybrid.EciesAeadHkdfUtil');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Util = goog.require('tink.Util');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey} = goog.require('google3.third_party.tink.javascript.internal.proto');
// This file contains only functions which are useful for implementation of
diff --git a/javascript/hybrid/ecies_aead_hkdf_util_test.js b/javascript/hybrid/ecies_aead_hkdf_util_test.js
index 4046be3..4621bde 100644
--- a/javascript/hybrid/ecies_aead_hkdf_util_test.js
+++ b/javascript/hybrid/ecies_aead_hkdf_util_test.js
@@ -16,10 +16,10 @@
goog.setTestOnly('tink.hybrid.EciesAeadHkdfUtilTest');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const EciesAeadHkdfUtil = goog.require('tink.hybrid.EciesAeadHkdfUtil');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Util = goog.require('tink.Util');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEciesAeadDemParams, PbEciesAeadHkdfParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbEciesHkdfKemParams, PbEllipticCurveType, PbHashType, PbKeyTemplate, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {assertExists} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/hybrid/ecies_aead_hkdf_validators.js b/javascript/hybrid/ecies_aead_hkdf_validators.js
index 9e4d147..0055081 100644
--- a/javascript/hybrid/ecies_aead_hkdf_validators.js
+++ b/javascript/hybrid/ecies_aead_hkdf_validators.js
@@ -16,7 +16,7 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const {PbEciesAeadDemParams, PbEciesAeadHkdfKeyFormat, PbEciesAeadHkdfParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbEciesHkdfKemParams, PbEllipticCurveType, PbHashType, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/hybrid/ecies_aead_hkdf_validators_test.js b/javascript/hybrid/ecies_aead_hkdf_validators_test.js
index 892c00c..c6a6c27 100644
--- a/javascript/hybrid/ecies_aead_hkdf_validators_test.js
+++ b/javascript/hybrid/ecies_aead_hkdf_validators_test.js
@@ -16,10 +16,10 @@
goog.setTestOnly('tink.hybrid.EciesAeadHkdfValidatorsTest');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const EciesAeadHkdfValidators = goog.require('tink.hybrid.EciesAeadHkdfValidators');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Util = goog.require('tink.Util');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEciesAeadDemParams, PbEciesAeadHkdfKeyFormat, PbEciesAeadHkdfParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbEciesHkdfKemParams, PbEllipticCurveType, PbHashType, PbKeyTemplate, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {assertExists} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/hybrid/encrypt_wrapper.ts b/javascript/hybrid/encrypt_wrapper.ts
index d1100d0..ff06bfe 100644
--- a/javascript/hybrid/encrypt_wrapper.ts
+++ b/javascript/hybrid/encrypt_wrapper.ts
@@ -1,5 +1,5 @@
import HybridEncryptWrapper from 'goog:tink.hybrid.HybridEncryptWrapper'; // from //third_party/tink/javascript/hybrid:hybrid_wrappers
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export function register() {
Registry.registerPrimitiveWrapper(new HybridEncryptWrapper());
diff --git a/javascript/hybrid/hybrid_config.js b/javascript/hybrid/hybrid_config.js
index 1784995..ebdb0de 100644
--- a/javascript/hybrid/hybrid_config.js
+++ b/javascript/hybrid/hybrid_config.js
@@ -19,7 +19,7 @@
const EciesAeadHkdfPublicKeyManager = goog.require('tink.hybrid.EciesAeadHkdfPublicKeyManager');
const HybridDecryptWrapper = goog.require('tink.hybrid.HybridDecryptWrapper');
const HybridEncryptWrapper = goog.require('tink.hybrid.HybridEncryptWrapper');
-const Registry = goog.require('tink.Registry');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
// Static methods and constants for registering with the Registry all instances
// of key types for hybrid encryption and decryption supported in a particular
diff --git a/javascript/hybrid/hybrid_config_test.js b/javascript/hybrid/hybrid_config_test.js
index d59706e..81dfa00 100644
--- a/javascript/hybrid/hybrid_config_test.js
+++ b/javascript/hybrid/hybrid_config_test.js
@@ -21,9 +21,9 @@
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
const HybridKeyTemplates = goog.require('tink.hybrid.HybridKeyTemplates');
-const KeysetHandle = goog.require('tink.KeysetHandle');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const {KeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.keyset_handle');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {PbKeyData, PbKeyStatusType, PbKeyTemplate, PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('hybrid config test', function() {
diff --git a/javascript/hybrid/hybrid_decrypt_wrapper.js b/javascript/hybrid/hybrid_decrypt_wrapper.js
index d478744..3ebd9d5 100644
--- a/javascript/hybrid/hybrid_decrypt_wrapper.js
+++ b/javascript/hybrid/hybrid_decrypt_wrapper.js
@@ -14,10 +14,10 @@
goog.module('tink.hybrid.HybridDecryptWrapper');
-const CryptoFormat = goog.require('tink.CryptoFormat');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbKeyStatusType} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/hybrid/hybrid_decrypt_wrapper_test.js b/javascript/hybrid/hybrid_decrypt_wrapper_test.js
index b78e0b1..a9daed1 100644
--- a/javascript/hybrid/hybrid_decrypt_wrapper_test.js
+++ b/javascript/hybrid/hybrid_decrypt_wrapper_test.js
@@ -15,13 +15,13 @@
goog.module('tink.hybrid.HybridDecryptWrapperTest');
goog.setTestOnly('tink.hybrid.HybridDecryptWrapperTest');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
const HybridDecryptWrapper = goog.require('tink.hybrid.HybridDecryptWrapper');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
const HybridEncryptWrapper = goog.require('tink.hybrid.HybridEncryptWrapper');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const Random = goog.require('tink.subtle.Random');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/hybrid/hybrid_encrypt_wrapper.js b/javascript/hybrid/hybrid_encrypt_wrapper.js
index d72c73b..c8a99af 100644
--- a/javascript/hybrid/hybrid_encrypt_wrapper.js
+++ b/javascript/hybrid/hybrid_encrypt_wrapper.js
@@ -14,10 +14,10 @@
goog.module('tink.hybrid.HybridEncryptWrapper');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
/**
diff --git a/javascript/hybrid/hybrid_encrypt_wrapper_test.js b/javascript/hybrid/hybrid_encrypt_wrapper_test.js
index aa94837..a7d9bc7 100644
--- a/javascript/hybrid/hybrid_encrypt_wrapper_test.js
+++ b/javascript/hybrid/hybrid_encrypt_wrapper_test.js
@@ -15,11 +15,11 @@
goog.module('tink.hybrid.HybridEncryptWrapperTest');
goog.setTestOnly('tink.hybrid.HybridEncryptWrapperTest');
-const CryptoFormat = goog.require('tink.CryptoFormat');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
const HybridEncryptWrapper = goog.require('tink.hybrid.HybridEncryptWrapper');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const Random = goog.require('tink.subtle.Random');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('hybrid encrypt wrapper test', function() {
diff --git a/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper.js b/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper.js
index 8a69887..69ef2de 100644
--- a/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper.js
+++ b/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper.js
@@ -16,8 +16,8 @@
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
const AeadConfig = goog.require('tink.aead.AeadConfig');
-const EciesAeadHkdfDemHelper = goog.require('tink.subtle.EciesAeadHkdfDemHelper');
-const Registry = goog.require('tink.Registry');
+const {EciesAeadHkdfDemHelper} = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_dem_helper');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesGcmKey, PbAesGcmKeyFormat, PbKeyTemplate} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper_test.js b/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper_test.js
index bb07598..26e9325 100644
--- a/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper_test.js
+++ b/javascript/hybrid/registry_ecies_aead_hkdf_dem_helper_test.js
@@ -17,8 +17,8 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const RegistryEciesAeadHkdfDemHelper = goog.require('tink.hybrid.RegistryEciesAeadHkdfDemHelper');
describe('registry ecies aead hkdf dem helper test', function() {
diff --git a/javascript/index.ts b/javascript/index.ts
index 100ceb1..5fa44f7 100644
--- a/javascript/index.ts
+++ b/javascript/index.ts
@@ -1 +1 @@
-export * from './keyset_handle';
+export {generateNew as generateNewKeysetHandle, KeysetHandle} from './keyset_handle';
diff --git a/javascript/binary_keyset_reader.js b/javascript/internal/binary_keyset_reader.ts
similarity index 62%
rename from javascript/binary_keyset_reader.js
rename to javascript/internal/binary_keyset_reader.ts
index c98441a..a6290dd 100644
--- a/javascript/binary_keyset_reader.js
+++ b/javascript/internal/binary_keyset_reader.ts
@@ -11,32 +11,21 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
-goog.module('tink.BinaryKeysetReader');
-
-const KeysetReader = goog.require('tink.KeysetReader');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const {PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
+import {KeysetReader} from './keyset_reader';
+import {PbEncryptedKeyset, PbKeyset} from './proto';
/**
* BinaryKeysetReader knows how to read a keyset or an encrypted keyset
* serialized to binary format.
*
- * @implements {KeysetReader}
* @final
*/
-class BinaryKeysetReader {
- /** @param {!Uint8Array} serializedKeyset */
- constructor(serializedKeyset) {
- /** @const @private {!Uint8Array} */
- this.serializedKeyset_ = serializedKeyset;
- }
+export class BinaryKeysetReader implements KeysetReader {
+ constructor(private readonly serializedKeyset: Uint8Array) {}
- /**
- * @param {!Uint8Array} serializedKeyset
- * @return {!BinaryKeysetReader}
- */
- static withUint8Array(serializedKeyset) {
+ static withUint8Array(serializedKeyset: Uint8Array): BinaryKeysetReader {
if (!serializedKeyset) {
throw new SecurityException('Serialized keyset has to be non-null.');
}
@@ -45,9 +34,9 @@
/** @override */
read() {
- let /** !PbKeyset */ keyset;
+ let keyset: PbKeyset;
try {
- keyset = PbKeyset.deserializeBinary(this.serializedKeyset_);
+ keyset = PbKeyset.deserializeBinary(this.serializedKeyset);
} catch (e) {
throw new SecurityException(
'Could not parse the given serialized proto as a keyset proto.');
@@ -60,9 +49,7 @@
}
/** @override */
- readEncrypted() {
+ readEncrypted(): PbEncryptedKeyset {
throw new SecurityException('Not implemented yet.');
}
}
-
-exports = BinaryKeysetReader;
diff --git a/javascript/binary_keyset_reader_test.js b/javascript/internal/binary_keyset_reader_test.js
similarity index 95%
rename from javascript/binary_keyset_reader_test.js
rename to javascript/internal/binary_keyset_reader_test.js
index 0ca8e3b..ee9f505 100644
--- a/javascript/binary_keyset_reader_test.js
+++ b/javascript/internal/binary_keyset_reader_test.js
@@ -15,8 +15,8 @@
goog.module('tink.BinaryKeysetReaderTest');
goog.setTestOnly('tink.BinaryKeysetReaderTest');
-const BinaryKeysetReader = goog.require('tink.BinaryKeysetReader');
-const Random = goog.require('tink.subtle.Random');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {BinaryKeysetReader} = goog.require('google3.third_party.tink.javascript.internal.binary_keyset_reader');
const {PbKeyData, PbKeyStatusType, PbKeyset, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('binary keyset reader test', function() {
diff --git a/javascript/binary_keyset_writer.js b/javascript/internal/binary_keyset_writer.ts
similarity index 73%
rename from javascript/binary_keyset_writer.js
rename to javascript/internal/binary_keyset_writer.ts
index 34867d7..dc7e256 100644
--- a/javascript/binary_keyset_writer.js
+++ b/javascript/internal/binary_keyset_writer.ts
@@ -11,27 +11,20 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.BinaryKeysetWriter');
-
-const KeysetWriter = goog.require('tink.KeysetWriter');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
+import {SecurityException} from '../exception/security_exception';
+import {KeysetWriter} from './keyset_writer';
/**
* KeysetWriter knows how to write a keyset or an encrypted keyset.
*
- * @implements {KeysetWriter}
* @final
*/
-class BinaryKeysetWriter {
+export class BinaryKeysetWriter implements KeysetWriter {
/** @override */
- write(keyset) {
+ write(keyset: AnyDuringMigration) {
if (!keyset) {
throw new SecurityException('keyset has to be non-null.');
}
return keyset.serializeBinary();
}
}
-
-exports = BinaryKeysetWriter;
diff --git a/javascript/binary_keyset_writer_test.js b/javascript/internal/binary_keyset_writer_test.js
similarity index 85%
rename from javascript/binary_keyset_writer_test.js
rename to javascript/internal/binary_keyset_writer_test.js
index 1526ef9..cd4a300 100644
--- a/javascript/binary_keyset_writer_test.js
+++ b/javascript/internal/binary_keyset_writer_test.js
@@ -15,8 +15,8 @@
goog.module('tink.BinaryKeysetWriterTest');
goog.setTestOnly('tink.BinaryKeysetWriterTest');
-const BinaryKeysetReader = goog.require('tink.BinaryKeysetReader');
-const BinaryKeysetWriter = goog.require('tink.BinaryKeysetWriter');
+const {BinaryKeysetReader} = goog.require('google3.third_party.tink.javascript.internal.binary_keyset_reader');
+const {BinaryKeysetWriter} = goog.require('google3.third_party.tink.javascript.internal.binary_keyset_writer');
const {createKeyset} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
describe('binary keyset writer test', function() {
diff --git a/javascript/cleartext_keyset_handle.js b/javascript/internal/cleartext_keyset_handle.ts
similarity index 65%
rename from javascript/cleartext_keyset_handle.js
rename to javascript/internal/cleartext_keyset_handle.ts
index bcd3463..d44c1a7 100644
--- a/javascript/cleartext_keyset_handle.js
+++ b/javascript/internal/cleartext_keyset_handle.ts
@@ -11,15 +11,11 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
+import {BinaryKeysetReader} from './binary_keyset_reader';
+import {BinaryKeysetWriter} from './binary_keyset_writer';
+import {KeysetHandle} from './keyset_handle';
+import {PbKeyset} from './proto';
-goog.module('tink.CleartextKeysetHandle');
-
-const BinaryKeysetReader = goog.require('tink.BinaryKeysetReader');
-const BinaryKeysetWriter = goog.require('tink.BinaryKeysetWriter');
-const KeysetHandle = goog.require('tink.KeysetHandle');
-const {PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
-
-/** @type {!BinaryKeysetWriter} */
const binaryKeysetWriter = new BinaryKeysetWriter();
/**
@@ -27,7 +23,7 @@
*
* @final
*/
-class CleartextKeysetHandle {
+export class CleartextKeysetHandle {
/**
* Creates a KeysetHandle from a JSPB array representation of a keyset. The
* array is used in place and not cloned.
@@ -35,10 +31,8 @@
* Note that JSPB is currently not open source, so this method can't be
* either.
*
- * @param {!Array<*>} keysetJspbArray
- * @return {!KeysetHandle}
*/
- static fromJspbArray(keysetJspbArray) {
+ static fromJspbArray(keysetJspbArray: AnyDuringMigration[]): KeysetHandle {
return new KeysetHandle(new PbKeyset(keysetJspbArray));
}
@@ -48,10 +42,8 @@
* Note that JSPB is currently not open source, so this method can't be
* either.
*
- * @param {string} keysetJspbString
- * @return {!KeysetHandle}
*/
- static deserializeFromJspb(keysetJspbString) {
+ static deserializeFromJspb(keysetJspbString: string): KeysetHandle {
return new KeysetHandle(PbKeyset.deserialize(keysetJspbString));
}
@@ -61,34 +53,26 @@
* Note that JSPB is currently not open source, so this method can't be
* either.
*
- * @param {!KeysetHandle} keysetHandle
- * @return {string}
*/
- static serializeToJspb(keysetHandle) {
+ static serializeToJspb(keysetHandle: KeysetHandle): string {
return keysetHandle.getKeyset().serialize();
}
/**
* Serializes a KeysetHandle to binary.
*
- * @param {!KeysetHandle} keysetHandle
- * @return {!Uint8Array}
*/
- static serializeToBinary(keysetHandle) {
+ static serializeToBinary(keysetHandle: KeysetHandle): Uint8Array {
return binaryKeysetWriter.write(keysetHandle.getKeyset());
}
/**
* Creates a KeysetHandle from a binary representation of a keyset.
*
- * @param {!Uint8Array} keysetBinary
- * @return {!KeysetHandle}
*/
- static deserializeFromBinary(keysetBinary) {
+ static deserializeFromBinary(keysetBinary: Uint8Array): KeysetHandle {
const reader = BinaryKeysetReader.withUint8Array(keysetBinary);
const keysetFromReader = reader.read();
return new KeysetHandle(keysetFromReader);
}
}
-
-exports = CleartextKeysetHandle;
diff --git a/javascript/cleartext_keyset_handle_test.js b/javascript/internal/cleartext_keyset_handle_test.js
similarity index 92%
rename from javascript/cleartext_keyset_handle_test.js
rename to javascript/internal/cleartext_keyset_handle_test.js
index f9ba9ac..b8cd34d 100644
--- a/javascript/cleartext_keyset_handle_test.js
+++ b/javascript/internal/cleartext_keyset_handle_test.js
@@ -15,8 +15,8 @@
goog.module('tink.CleartextKeysetHandleTest');
goog.setTestOnly();
-const CleartextKeysetHandle = goog.require('tink.CleartextKeysetHandle');
-const KeysetHandle = goog.require('tink.KeysetHandle');
+const {CleartextKeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.cleartext_keyset_handle');
+const {KeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.keyset_handle');
const {PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {createKeyset} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/internal/crypto_format.ts b/javascript/internal/crypto_format.ts
new file mode 100644
index 0000000..c513f4a
--- /dev/null
+++ b/javascript/internal/crypto_format.ts
@@ -0,0 +1,119 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
+import {SecurityException} from '../exception/security_exception';
+import {PbKeyset, PbOutputPrefixType} from './proto';
+
+/**
+ * Constants and methods that deal with the format of the outputs handled by
+ * Tink.
+ *
+ * @static
+ * @final
+ */
+export class CryptoFormat {
+ /**
+ * Generates the prefix for the outputs handled by the given 'key'.
+ * Throws an exception if the prefix type of 'key' is invalid.
+ *
+ *
+ */
+ static getOutputPrefix(key: PbKeyset.Key): Uint8Array {
+ switch (key.getOutputPrefixType()) {
+ case PbOutputPrefixType.LEGACY:
+
+ // fall through
+ case PbOutputPrefixType.CRUNCHY:
+ return CryptoFormat.makeOutputPrefix_(
+ key.getKeyId(), CryptoFormat.LEGACY_START_BYTE);
+ case PbOutputPrefixType.TINK:
+ return CryptoFormat.makeOutputPrefix_(
+ key.getKeyId(), CryptoFormat.TINK_START_BYTE);
+ case PbOutputPrefixType.RAW:
+ return CryptoFormat.RAW_PREFIX;
+ default:
+ throw new SecurityException('Unsupported key prefix type.');
+ }
+ }
+
+ /**
+ * Makes output prefix which consits of 4 bytes of key id in Big Endian
+ * representation followed by 1 byte of key type identifier.
+ *
+ * @static
+ *
+ */
+ private static makeOutputPrefix_(keyId: number, keyTypeIdentifier: number):
+ Uint8Array {
+ let res: AnyDuringMigration[] = [keyTypeIdentifier];
+ res = res.concat(CryptoFormat.numberAsBigEndian_(keyId));
+ return new Uint8Array(res);
+ }
+
+ /**
+ * Returns the given number as Uint8Array in Big Endian format.
+ *
+ * Given number has to be a non-negative integer smaller than 2^32.
+ *
+ * @static
+ *
+ */
+ private static numberAsBigEndian_(n: number): AnyDuringMigration[] {
+ if (!Number.isInteger(n) || n < 0 || n >= 2 ** 32) {
+ throw new InvalidArgumentsException(
+ 'Number has to be unsigned 32-bit integer.');
+ }
+ const numberOfBytes = 4;
+ const res = new Array(numberOfBytes);
+ for (let i = 0; i < numberOfBytes; i++) {
+ res[i] = 255 & n >> 8 * (numberOfBytes - i - 1);
+ }
+ return res;
+ }
+
+ /**
+ * Prefix size of Tink and Legacy key types.
+ */
+ static readonly NON_RAW_PREFIX_SIZE = 5;
+
+ /**
+ * Prefix size of Legacy key types.
+ */
+ static readonly LEGACY_PREFIX_SIZE = CryptoFormat.NON_RAW_PREFIX_SIZE;
+
+ /**
+ * Legacy starts with 0 and is followed by 4-byte key id.
+ */
+ static readonly LEGACY_START_BYTE = 0;
+
+ /**
+ * Prefix size of Tink key types.
+ */
+ static readonly TINK_PREFIX_SIZE = CryptoFormat.NON_RAW_PREFIX_SIZE;
+
+ /**
+ * Tink starts with 1 and is followed by 4-byte key id.
+ */
+ static readonly TINK_START_BYTE = 1;
+
+ /**
+ * Raw prefix should have length 0.
+ */
+ static readonly RAW_PREFIX_SIZE = 0;
+
+ /**
+ * Raw prefix is empty Uint8Array.
+ */
+ static readonly RAW_PREFIX = new Uint8Array(0);
+}
diff --git a/javascript/crypto_format_test.js b/javascript/internal/crypto_format_test.js
similarity index 96%
rename from javascript/crypto_format_test.js
rename to javascript/internal/crypto_format_test.js
index 7d116be..1e69ef6 100644
--- a/javascript/crypto_format_test.js
+++ b/javascript/internal/crypto_format_test.js
@@ -15,7 +15,7 @@
goog.module('tink.CryptoFormatTest');
goog.setTestOnly('tink.CryptoFormatTest');
-const CryptoFormat = goog.require('tink.CryptoFormat');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
const {PbKeysetKey: PbKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('crypto format test', function() {
diff --git a/javascript/key_manager.js b/javascript/internal/key_manager.ts
similarity index 66%
rename from javascript/key_manager.js
rename to javascript/internal/key_manager.ts
index 70fceec..40b079b 100644
--- a/javascript/key_manager.js
+++ b/javascript/internal/key_manager.ts
@@ -11,50 +11,38 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.KeyManager');
-
-const {PbKeyData, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
+import {PbKeyData, PbMessage} from './proto';
/**
* An auxiliary container for methods that generate new keys.
* Those methods are separate from KeyManager as their functionality is
* independent of the primitive of the corresponding KeyManager.
*
- * @record
*/
-class KeyFactory {
+export interface KeyFactory {
/**
* Generates a new random key according to 'keyFormat'.
*
- * @param {!PbMessage|!Uint8Array} keyFormat is either a KeyFormat
+ * @param keyFormat is either a KeyFormat
* proto or a serialized KeyFormat proto
- * @return {!PbMessage|!Promise<!PbMessage>} the new generated key
+ * @return the new generated key
*/
- newKey(keyFormat) {}
+ newKey(keyFormat: PbMessage|Uint8Array): PbMessage|Promise<PbMessage>;
/**
* Generates a new random key based on the "serialized_key_format" and returns
* it as a KeyData proto.
*
- * @param {!Uint8Array} serializedKeyFormat
- * @return {!PbKeyData|!Promise<!PbKeyData>}
*/
- newKeyData(serializedKeyFormat) {}
+ newKeyData(serializedKeyFormat: Uint8Array): PbKeyData|Promise<PbKeyData>;
}
-/**
- * @record
- * @extends {KeyFactory}
- */
-class PrivateKeyFactory {
+export interface PrivateKeyFactory extends KeyFactory {
/**
* Returns a public key data extracted from the given serialized private key.
*
- * @param {!Uint8Array} serializedPrivateKey
- * @return {!PbKeyData}
*/
- getPublicKeyData(serializedPrivateKey) {}
+ getPublicKeyData(serializedPrivateKey: Uint8Array): PbKeyData;
}
/**
@@ -66,35 +54,28 @@
*
* The template parameter P denotes the primitive corresponding to the keys
* handled by this manager.
- *
- * @template P
- * @record
*/
-class KeyManager {
+export interface KeyManager<P> {
/**
* Constructs an instance of primitive P for a given key.
*
- * @param {!Object} primitiveType
- * @param {!PbKeyData|!PbMessage} key is either a KeyData proto or a supported
+ * @param key is either a KeyData proto or a supported
* key proto
- * @return {!Promise.<!P>}
*/
- getPrimitive(primitiveType, key) {}
+ getPrimitive(primitiveType: AnyDuringMigration, key: PbKeyData|PbMessage):
+ Promise<P>;
/**
* Returns true if this KeyManager supports keyType.
*
- * @param {string} keyType
- * @return {boolean}
*/
- doesSupport(keyType) {}
+ doesSupport(keyType: string): boolean;
/**
* Returns the URL which identifies the keys managed by this KeyManager.
*
- * @return {string}
*/
- getKeyType() {}
+ getKeyType(): string;
/**
* Returns the type of primitive which can be generated by this KeyManager.
@@ -103,28 +84,19 @@
* the primitive returned by getPrimitive function implements certain
* primitive interface (e.g. that the primitive is AEAD).
*
- * @return {!Object}
*/
- getPrimitiveType() {}
+ getPrimitiveType(): AnyDuringMigration;
/**
* Returns the version of this KeyManager.
*
- * @return {number}
*/
- getVersion() {}
+ getVersion(): number;
/**
* Returns a factory that generates keys of the key type handled by this
* manager.
*
- * @return {!KeyFactory}
*/
- getKeyFactory() {}
+ getKeyFactory(): KeyFactory;
}
-
-exports = {
- KeyManager,
- KeyFactory,
- PrivateKeyFactory
-};
diff --git a/javascript/internal/keyset_handle.ts b/javascript/internal/keyset_handle.ts
new file mode 100644
index 0000000..4bcdf4d
--- /dev/null
+++ b/javascript/internal/keyset_handle.ts
@@ -0,0 +1,206 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+import {Aead} from '../aead/internal/aead';
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
+import {SecurityException} from '../exception/security_exception';
+import * as Random from '../subtle/random';
+
+import * as KeyManager from './key_manager';
+import {KeysetReader} from './keyset_reader';
+import {KeysetWriter} from './keyset_writer';
+import * as PrimitiveSet from './primitive_set';
+import {PbKeyMaterialType, PbKeyset, PbKeyStatusType, PbKeyTemplate} from './proto';
+import * as Registry from './registry';
+import * as Util from './util';
+
+/**
+ * Keyset handle provide abstracted access to Keysets, to limit the exposure of
+ * actual protocol buffers that hold sensitive key material.
+ *
+ * @final
+ */
+export class KeysetHandle {
+ private readonly keyset_: PbKeyset;
+
+ constructor(keyset: PbKeyset) {
+ Util.validateKeyset(keyset);
+ this.keyset_ = keyset;
+ }
+
+ /**
+ * Returns a primitive that uses key material from this keyset handle. If
+ * opt_customKeyManager is defined then the provided key manager is used to
+ * instantiate primitives. Otherwise key manager from Registry is used.
+ */
+ async getPrimitive<P>(
+ primitiveType: Util.Constructor<P>,
+ opt_customKeyManager?: KeyManager.KeyManager<P>|null): Promise<P> {
+ if (!primitiveType) {
+ throw new InvalidArgumentsException('primitive type must be non-null');
+ }
+ const primitiveSet =
+ await this.getPrimitiveSet(primitiveType, opt_customKeyManager);
+ return Registry.wrap(primitiveSet);
+ }
+
+ /**
+ * Creates a set of primitives corresponding to the keys with status Enabled
+ * in the given keysetHandle, assuming all the correspoding key managers are
+ * present (keys with status different from Enabled are skipped). If provided
+ * uses customKeyManager instead of registered key managers for keys supported
+ * by the customKeyManager.
+ *
+ * Visible for testing.
+ */
+ async getPrimitiveSet<P>(
+ primitiveType: Util.Constructor<P>,
+ opt_customKeyManager?: KeyManager.KeyManager<P>|
+ null): Promise<PrimitiveSet.PrimitiveSet<P>> {
+ const primitiveSet = new PrimitiveSet.PrimitiveSet<P>(primitiveType);
+ const keys = this.keyset_.getKeyList();
+ const keysLength = keys.length;
+ for (let i = 0; i < keysLength; i++) {
+ const key = keys[i];
+ if (key.getStatus() === PbKeyStatusType.ENABLED) {
+ const keyData = key.getKeyData();
+ if (!keyData) {
+ throw new SecurityException('Key data has to be non null.');
+ }
+ let primitive;
+ if (opt_customKeyManager &&
+ opt_customKeyManager.getKeyType() === keyData.getTypeUrl()) {
+ primitive =
+ await opt_customKeyManager.getPrimitive(primitiveType, keyData);
+ } else {
+ primitive = await Registry.getPrimitive<P>(primitiveType, keyData);
+ }
+ const entry = primitiveSet.addPrimitive(primitive, key);
+ if (key.getKeyId() === this.keyset_.getPrimaryKeyId()) {
+ primitiveSet.setPrimary(entry);
+ }
+ }
+ }
+ return primitiveSet;
+ }
+
+ /**
+ * Encrypts the underlying keyset with the provided masterKeyAead wnd writes
+ * the resulting encryptedKeyset to the given writer which must be non-null.
+ *
+ *
+ */
+ async write(writer: KeysetWriter, masterKeyAead: Aead) {
+ // TODO implement
+ throw new SecurityException('KeysetHandle -- write: Not implemented yet.');
+ }
+
+ /**
+ * Returns the keyset held by this KeysetHandle.
+ *
+ */
+ getKeyset(): PbKeyset {
+ return this.keyset_;
+ }
+}
+
+/**
+ * Creates a KeysetHandle from an encrypted keyset obtained via reader, using
+ * masterKeyAead to decrypt the keyset.
+ *
+ *
+ */
+export async function read(
+ reader: KeysetReader, masterKeyAead: Aead): Promise<KeysetHandle> {
+ // TODO implement
+ throw new SecurityException('KeysetHandle -- read: Not implemented yet.');
+}
+
+/**
+ * Returns a new KeysetHandle that contains a single new key generated
+ * according to keyTemplate.
+ *
+ *
+ */
+export async function generateNew(keyTemplate: PbKeyTemplate):
+ Promise<KeysetHandle> {
+ // TODO(thaidn): move this to a key manager.
+ const keyset = await generateNewKeyset_(keyTemplate);
+ return new KeysetHandle(keyset);
+}
+
+/**
+ * Generates a new Keyset that contains a single new key generated
+ * according to keyTemplate.
+ *
+ */
+async function generateNewKeyset_(keyTemplate: PbKeyTemplate):
+ Promise<PbKeyset> {
+ const key = (new PbKeyset.Key())
+ .setStatus(PbKeyStatusType.ENABLED)
+ .setOutputPrefixType(keyTemplate.getOutputPrefixType());
+ const keyId = generateNewKeyId_();
+ key.setKeyId(keyId);
+ const keyData = await Registry.newKeyData(keyTemplate);
+ key.setKeyData(keyData);
+ const keyset = new PbKeyset();
+ keyset.addKey(key);
+ keyset.setPrimaryKeyId(keyId);
+ return keyset;
+}
+
+/**
+ * Generates a new random key ID.
+ *
+ * @return The key ID.
+ */
+function generateNewKeyId_(): number {
+ const bytes = Random.randBytes(4);
+ let value = 0;
+ for (let i = 0; i < bytes.length; i++) {
+ value += (bytes[i] & 255) << i * 8;
+ }
+
+ // Make sure the key ID is a positive integer smaller than 2^32.
+ return Math.abs(value) % 2 ** 32;
+}
+
+/**
+ * Creates a KeysetHandle from a keyset, obtained via reader, which
+ * must contain no secret key material.
+ *
+ * This can be used to load public keysets or envelope encryption keysets.
+ * Users that need to load cleartext keysets can use CleartextKeysetHandle.
+ *
+ */
+export function readNoSecret(reader: KeysetReader): KeysetHandle {
+ if (reader === null) {
+ throw new SecurityException('Reader has to be non-null.');
+ }
+ const keyset = reader.read();
+ const keyList = keyset.getKeyList();
+ for (const key of keyList) {
+ const keyData = key.getKeyData();
+ if (keyData) {
+ switch (keyData.getKeyMaterialType()) {
+ case PbKeyMaterialType.ASYMMETRIC_PUBLIC:
+
+ // fall through
+ case PbKeyMaterialType.REMOTE:
+ continue;
+ }
+ }
+ throw new SecurityException('Keyset contains secret key material.');
+ }
+ return new KeysetHandle(keyset);
+}
diff --git a/javascript/keyset_handle_test.js b/javascript/internal/keyset_handle_test.js
similarity index 96%
rename from javascript/keyset_handle_test.js
rename to javascript/internal/keyset_handle_test.js
index 14be702..ca18839 100644
--- a/javascript/keyset_handle_test.js
+++ b/javascript/internal/keyset_handle_test.js
@@ -15,22 +15,22 @@
goog.module('tink.KeysetHandleTest');
goog.setTestOnly('tink.KeysetHandleTest');
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const BinaryKeysetReader = goog.require('tink.BinaryKeysetReader');
-const BinaryKeysetWriter = goog.require('tink.BinaryKeysetWriter');
-const Bytes = goog.require('tink.subtle.Bytes');
-const CleartextKeysetHandle = goog.require('tink.CleartextKeysetHandle');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const HybridConfig = goog.require('tink.hybrid.HybridConfig');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
+const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
+const {BinaryKeysetReader} = goog.require('google3.third_party.tink.javascript.internal.binary_keyset_reader');
+const {BinaryKeysetWriter} = goog.require('google3.third_party.tink.javascript.internal.binary_keyset_writer');
+const {CleartextKeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.cleartext_keyset_handle');
const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
-const KeyManager = goog.require('tink.KeyManager');
-const KeysetHandle = goog.require('tink.KeysetHandle');
+const {KeysetHandle, generateNew, read, readNoSecret} = goog.require('google3.third_party.tink.javascript.internal.keyset_handle');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbKeyData, PbKeyMaterialType, PbKeyStatusType, PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
+const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {createKeyset} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
describe('keyset handle test', function() {
@@ -83,13 +83,13 @@
// tests for read method
it('read', async function() {
const keyTemplate = AeadKeyTemplates.aes128CtrHmacSha256();
- const keysetHandle = await KeysetHandle.generateNew(keyTemplate);
+ const keysetHandle = await generateNew(keyTemplate);
const serializedKeyset =
CleartextKeysetHandle.serializeToBinary(keysetHandle);
const keysetReader = new BinaryKeysetReader(serializedKeyset);
const aead = await keysetHandle.getPrimitive(Aead);
try {
- await KeysetHandle.read(keysetReader, aead);
+ await read(keysetReader, aead);
} catch (e) {
expect(e.toString())
.toBe(
@@ -103,7 +103,7 @@
// tests for generateNew method
it('generate new', async function() {
const keyTemplate = AeadKeyTemplates.aes128CtrHmacSha256();
- const keysetHandle = await KeysetHandle.generateNew(keyTemplate);
+ const keysetHandle = await generateNew(keyTemplate);
const keyset = keysetHandle.getKeyset();
expect(1).toBe(keyset.getKeyList().length);
@@ -528,7 +528,7 @@
const reader =
BinaryKeysetReader.withUint8Array(keyset.serializeBinary());
try {
- KeysetHandle.readNoSecret(reader);
+ readNoSecret(reader);
fail('An exception should be thrown.');
} catch (e) {
expect(e.toString())
@@ -552,7 +552,7 @@
keyset.setPrimaryKeyId(1);
const reader = BinaryKeysetReader.withUint8Array(keyset.serializeBinary());
- const keysetHandle = KeysetHandle.readNoSecret(reader);
+ const keysetHandle = readNoSecret(reader);
expect(keysetHandle.getKeyset()).toEqual(keyset);
});
diff --git a/javascript/keyset_reader.js b/javascript/internal/keyset_reader.ts
similarity index 75%
rename from javascript/keyset_reader.js
rename to javascript/internal/keyset_reader.ts
index 3fe9ac3..245dbdb 100644
--- a/javascript/keyset_reader.js
+++ b/javascript/internal/keyset_reader.ts
@@ -11,31 +11,23 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.KeysetReader');
-
-const {PbEncryptedKeyset, PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
+import {PbEncryptedKeyset, PbKeyset} from './proto';
/**
* KeysetReader knows how to read a keyset or an encrypted keyset from some
* source.
*
- * @record
*/
-class KeysetReader {
+export interface KeysetReader {
/**
* Reads and returns a (cleartext) Keyset object from the underlying source.
*
- * @return {!PbKeyset}
*/
- read() {}
+ read(): PbKeyset;
/**
* Reads and returns an EncryptedKeyset from the underlying source.
*
- * @return {!PbEncryptedKeyset}
*/
- readEncrypted() {}
+ readEncrypted(): PbEncryptedKeyset;
}
-
-exports = KeysetReader;
diff --git a/javascript/keyset_writer.js b/javascript/internal/keyset_writer.ts
similarity index 70%
rename from javascript/keyset_writer.js
rename to javascript/internal/keyset_writer.ts
index cc715df..ffd461c 100644
--- a/javascript/keyset_writer.js
+++ b/javascript/internal/keyset_writer.ts
@@ -11,23 +11,13 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.KeysetWriter');
-
-const {PbEncryptedKeyset, PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
+import {PbEncryptedKeyset, PbKeyset} from './proto';
/**
* KeysetWriter knows how to write a keyset or an encrypted keyset to some
* storage system.
*
- * @record
*/
-class KeysetWriter {
- /**
- * @param {!PbKeyset|!PbEncryptedKeyset} keyset
- * @return {!Uint8Array}
- */
- write(keyset) {}
+export interface KeysetWriter {
+ write(keyset: PbKeyset|PbEncryptedKeyset): Uint8Array;
}
-
-exports = KeysetWriter;
diff --git a/javascript/primitive_set.js b/javascript/internal/primitive_set.ts
similarity index 61%
rename from javascript/primitive_set.js
rename to javascript/internal/primitive_set.ts
index decfa52..c6b3e4d 100644
--- a/javascript/primitive_set.js
+++ b/javascript/internal/primitive_set.ts
@@ -11,12 +11,11 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
-goog.module('tink.PrimitiveSet');
-
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const {PbKeyStatusType, PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
+import {CryptoFormat} from './crypto_format';
+import {PbKeyset, PbKeyStatusType, PbOutputPrefixType} from './proto';
+import {Constructor} from './util';
/**
* Auxiliary class for PrimitiveSet
@@ -25,50 +24,26 @@
* @template P
* @final
*/
-class Entry {
- /**
- * @param {!P} primitive
- * @param {!Uint8Array} identifier
- * @param {!PbKeyStatusType} keyStatus
- * @param {!PbOutputPrefixType} outputPrefixType
- */
- constructor(primitive, identifier, keyStatus, outputPrefixType) {
- /** @const @private {!P} */
- this.primitive_ = primitive;
- /** @const @private {!Uint8Array} */
- this.identifier_ = identifier;
- /** @const @private {!PbKeyStatusType} */
- this.status_ = keyStatus;
- /** @const @private {!PbOutputPrefixType} */
- this.outputPrefixType_ = outputPrefixType;
+export class Entry<P> {
+ constructor(
+ private readonly primitive: P, private readonly identifier: Uint8Array,
+ private readonly keyStatus: PbKeyStatusType,
+ private readonly outputPrefixType: PbOutputPrefixType) {}
+
+ getPrimitive(): P {
+ return this.primitive;
}
- /**
- * @return {!P}
- */
- getPrimitive() {
- return this.primitive_;
+ getIdentifier(): Uint8Array {
+ return this.identifier;
}
- /**
- * @return {!Uint8Array}
- */
- getIdentifier() {
- return this.identifier_;
+ getKeyStatus(): PbKeyStatusType {
+ return this.keyStatus;
}
- /**
- * @return {!PbKeyStatusType}
- */
- getKeyStatus() {
- return this.status_;
- }
-
- /**
- * @return {!PbOutputPrefixType}
- */
- getOutputPrefixType() {
- return this.outputPrefixType_;
+ getOutputPrefixType(): PbOutputPrefixType {
+ return this.outputPrefixType;
}
}
@@ -90,83 +65,62 @@
* PrimitiveSet is a public class to allow its use in implementations of custom
* primitives.
*
- * @template P
* @final
*/
-class PrimitiveSet {
- /**
- * @param {!Object} primitiveType
- */
- constructor(primitiveType) {
- /**
- * @private {!Object}
- */
- this.primitiveType_ = primitiveType;
- /**
- * @private {?Entry<P>}
- */
- this.primary_ = null;
- // Keys have to be stored as strings as two Uint8Arrays holding the same
- // digits are still different objects.
- /**
- * @private {!Map<string, !Array<!Entry<P>>>}
- */
+export class PrimitiveSet<P> {
+ private primary_: Entry<P>|null = null;
+
+ // Keys have to be stored as strings as two Uint8Arrays holding the same
+ // digits are still different objects.
+ private readonly identifierToPrimitivesMap_: Map<string, Array<Entry<P>>>;
+
+ constructor(private readonly primitiveType: Constructor<P>) {
this.identifierToPrimitivesMap_ = new Map();
}
/**
* Returns the type of primitives contained in this set.
*
- * @return {!Object}
*/
- getPrimitiveType() {
- return this.primitiveType_;
+ getPrimitiveType(): Constructor<P> {
+ return this.primitiveType;
}
/**
* Creates an entry in the primitive table and returns it.
*
- * @param {!P} primitive
- * @param {!PbKeyset.Key} key
*
- * @return {!Entry<P>}
*/
- addPrimitive(primitive, key) {
+ addPrimitive(primitive: P, key: PbKeyset.Key): Entry<P> {
if (!primitive) {
throw new SecurityException('Primitive has to be non null.');
}
if (!key) {
throw new SecurityException('Key has to be non null.');
}
-
const identifier = CryptoFormat.getOutputPrefix(key);
- const entry = new Entry(primitive, identifier, key.getStatus(),
- key.getOutputPrefixType());
-
+ const entry = new Entry(
+ primitive, identifier, key.getStatus(), key.getOutputPrefixType());
this.addPrimitiveToMap_(entry);
-
return entry;
}
/**
* Returns the entry with the primary primitive.
*
- * @return {?Entry<P>}
*/
- getPrimary() {
+ getPrimary(): Entry<P>|null {
return this.primary_;
}
/**
* Sets given Entry as the primary one.
*
- * @param {!Entry<P>} primitive
*/
- setPrimary(primitive) {
+ setPrimary(primitive: Entry<P>) {
if (!primitive) {
throw new SecurityException('Primary cannot be set to null.');
}
-
if (primitive.getKeyStatus() != PbKeyStatusType.ENABLED) {
throw new SecurityException('Primary has to be enabled.');
}
@@ -186,29 +140,24 @@
'Primary cannot be set to an entry which is ' +
'not held by this primitive set.');
}
-
this.primary_ = primitive;
}
/**
* Returns all primitives using RAW prefix.
*
- * @return {!Array<!Entry<P>>}
*/
- getRawPrimitives() {
+ getRawPrimitives(): Array<Entry<P>> {
return this.getPrimitives(CryptoFormat.RAW_PREFIX);
}
/**
* Returns the entries with primitive identified with identifier.
*
- * @param {!Uint8Array} identifier
*
- * @return {!Array<!Entry<P>>}
*/
- getPrimitives(identifier) {
+ getPrimitives(identifier: Uint8Array): Array<Entry<P>> {
const result = this.getPrimitivesFromMap_(identifier);
-
if (!result) {
return [];
} else {
@@ -219,12 +168,10 @@
/**
* Returns a set of primitives which corresponds to the given identifier.
*
- * @private
- * @param {!Uint8Array|string} identifier
*
- * @return {!Array<!Entry<P>>|undefined}
*/
- getPrimitivesFromMap_(identifier) {
+ private getPrimitivesFromMap_(identifier: Uint8Array|
+ string): Array<Entry<P>>|undefined {
if (identifier instanceof Uint8Array) {
identifier = [...identifier].toString();
}
@@ -234,15 +181,11 @@
/**
* Add primitive to map.
*
- * @private
- * @param {!Entry<P>} entry
*/
- addPrimitiveToMap_(entry) {
+ private addPrimitiveToMap_(entry: Entry<P>) {
const identifier = entry.getIdentifier();
const id = [...identifier].toString();
-
- let existing = this.getPrimitivesFromMap_(id);
-
+ const existing = this.getPrimitivesFromMap_(id);
if (!existing) {
this.identifierToPrimitivesMap_.set(id, [entry]);
} else {
@@ -251,8 +194,3 @@
}
}
}
-
-exports = {
- Entry,
- PrimitiveSet,
-};
diff --git a/javascript/primitive_set_test.js b/javascript/internal/primitive_set_test.js
similarity index 95%
rename from javascript/primitive_set_test.js
rename to javascript/internal/primitive_set_test.js
index cf2b9e6..cd3a4be 100644
--- a/javascript/primitive_set_test.js
+++ b/javascript/internal/primitive_set_test.js
@@ -15,11 +15,11 @@
goog.module('tink.PrimitiveSetTest');
goog.setTestOnly('tink.PrimitiveSetTest');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
+const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
describe('primitive set test', function() {
/////////////////////////////////////////////////////////////////////////////
@@ -39,6 +39,20 @@
fail('An exception should be thrown.');
});
+ it('add primitive null primitive', function() {
+ const primitive = null;
+ const key = createKey();
+ const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead);
+
+ try {
+ primitiveSet.addPrimitive(primitive, key);
+ } catch (e) {
+ expect(e.toString()).toBe(ExceptionText.addingNullPrimitive());
+ return;
+ }
+ fail('An exception should be thrown.');
+ });
+
it('add primitive multiple times should work', function() {
const key = createKey();
const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead);
diff --git a/javascript/primitive_wrapper.js b/javascript/internal/primitive_wrapper.ts
similarity index 77%
rename from javascript/primitive_wrapper.js
rename to javascript/internal/primitive_wrapper.ts
index 51e9ac8..bbc9d2d 100644
--- a/javascript/primitive_wrapper.js
+++ b/javascript/internal/primitive_wrapper.ts
@@ -11,10 +11,8 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.PrimitiveWrapper');
-
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
+import * as PrimitiveSet from './primitive_set';
+import {Constructor} from './util';
/**
* Basic interface for wrapping a primitive.
@@ -23,25 +21,17 @@
* cryptographic task. This is done by the PrimitiveWrapper. Whenever a new
* primitive type is added to Tink, the user should define a new
* PrimitiveWrapper and register it with the Registry.
- *
- * @template P
- * @record
*/
-class PrimitiveWrapper {
+export interface PrimitiveWrapper<P> {
/**
* Wraps a PrimitiveSet and returns a single instance.
*
- * @param {!PrimitiveSet.PrimitiveSet<P>} primitiveSet
- * @return {!P}
*/
- wrap(primitiveSet) {}
+ wrap(primitiveSet: PrimitiveSet.PrimitiveSet<P>): P;
/**
* Returns the type of the managed primitive. Used for internal management.
*
- * @return {!Object}
*/
- getPrimitiveType() {}
+ getPrimitiveType(): Constructor<P>;
}
-
-exports = PrimitiveWrapper;
diff --git a/javascript/proto_test.js b/javascript/internal/proto_test.js
similarity index 100%
rename from javascript/proto_test.js
rename to javascript/internal/proto_test.js
diff --git a/javascript/internal/registry.ts b/javascript/internal/registry.ts
new file mode 100644
index 0000000..0cad8b6
--- /dev/null
+++ b/javascript/internal/registry.ts
@@ -0,0 +1,244 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @fileoverview Registry for KeyManagers.
+ *
+ * Registry maps supported key types to corresponding KeyManager objects (i.e.
+ * the KeyManagers which may instantiate the primitive corresponding to the
+ * given key or generate new key of the given type). Keeping KeyManagers for all
+ * primitives in a single Registry (rather than having a separate keyManager per
+ * primitive) enables modular construction of compound primitives from "simple"
+ * ones (e.g. AES-CTR-HMAC AEAD encryption from IND-CPA encryption and MAC).
+ *
+ * Regular users will not usually work with Registry directly, but via primitive
+ * factories, which query Registry for the specific KeyManagers in the
+ * background.
+ */
+
+import {SecurityException} from '../exception/security_exception';
+
+import * as KeyManager from './key_manager';
+import * as PrimitiveSet from './primitive_set';
+import {PrimitiveWrapper} from './primitive_wrapper';
+import {PbKeyData, PbKeyTemplate, PbMessage} from './proto';
+
+// key managers maps
+const typeToManagerMap_:
+ Map<string, KeyManager.KeyManager<AnyDuringMigration>> = new Map();
+
+const typeToNewKeyAllowedMap_: Map<string, boolean> = new Map();
+
+// primitive wrappers map
+const primitiveTypeToWrapper_:
+ Map<AnyDuringMigration, PrimitiveWrapper<AnyDuringMigration>> = new Map();
+
+/**
+ * Register the given manager for the given key type. Manager must be
+ * non-nullptr. New keys are allowed if not specified.
+ */
+export function registerKeyManager<P>(
+ manager: KeyManager.KeyManager<P>, opt_newKeyAllowed?: boolean) {
+ if (opt_newKeyAllowed === undefined) {
+ opt_newKeyAllowed = true;
+ }
+ if (!manager) {
+ throw new SecurityException('Key manager cannot be null.');
+ }
+ const typeUrl = manager.getKeyType();
+ if (typeToManagerMap_.has(typeUrl)) {
+ // Cannot overwrite the existing key manager by a new one.
+ if (!(typeToManagerMap_.get(typeUrl) instanceof manager.constructor)) {
+ throw new SecurityException(
+ 'Key manager for key type ' + typeUrl +
+ ' has already been registered and cannot be overwritten.');
+ }
+
+ // It is forbidden to change new_key_allowed from false to true.
+ if (!typeToNewKeyAllowedMap_.get(typeUrl) && opt_newKeyAllowed) {
+ throw new SecurityException(
+ 'Key manager for key type ' + typeUrl +
+ ' has already been registered with forbidden new key operation.');
+ }
+ typeToNewKeyAllowedMap_.set(typeUrl, opt_newKeyAllowed);
+ }
+ typeToManagerMap_.set(typeUrl, manager);
+ typeToNewKeyAllowedMap_.set(typeUrl, opt_newKeyAllowed);
+}
+
+/**
+ * Returns a key manager for the given key type or throws an exception if no
+ * such manager found.
+ *
+ * @param typeUrl -- key type
+ *
+ */
+export function getKeyManager<P>(typeUrl: string): KeyManager.KeyManager<P> {
+ const res = typeToManagerMap_.get(typeUrl);
+ if (!res) {
+ throw new SecurityException(
+ 'Key manager for key type ' + typeUrl + ' has not been registered.');
+ }
+ return res;
+}
+
+/**
+ * It finds KeyManager according to key type (which is either given by
+ * PbKeyData or given by opt_typeUrl), than calls the corresponding
+ * manager's getPrimitive method.
+ *
+ * Either key is of type PbKeyData or opt_typeUrl must be provided.
+ *
+ * @param key -- key is either a proto of some key
+ * or key data.
+ * @param opt_typeUrl -- key type
+ * @this {typeof Registry}
+ *
+ */
+export async function getPrimitive<P>(
+ primitiveType: AnyDuringMigration, key: PbKeyData|PbMessage,
+ opt_typeUrl?: string|null): Promise<P> {
+ if (key instanceof PbKeyData) {
+ if (opt_typeUrl && key.getTypeUrl() != opt_typeUrl) {
+ throw new SecurityException(
+ 'Key type is ' + opt_typeUrl + ', but it is expected to be ' +
+ key.getTypeUrl() + ' or undefined.');
+ }
+ opt_typeUrl = key.getTypeUrl();
+ }
+ if (!opt_typeUrl) {
+ throw new SecurityException('Key type has to be specified.');
+ }
+ const manager = getKeyManager<P>(opt_typeUrl);
+ return manager.getPrimitive(primitiveType, key);
+}
+
+/**
+ * Generates a new PbKeyData for the specified keyTemplate. It finds a
+ * KeyManager given by keyTemplate.typeUrl and calls the newKeyData method of
+ * that manager.
+ *
+ *
+ *
+ */
+export async function newKeyData(keyTemplate: PbKeyTemplate):
+ Promise<PbKeyData> {
+ const manager = getKeyManagerWithNewKeyAllowedCheck_(keyTemplate);
+ return manager.getKeyFactory().newKeyData(keyTemplate.getValue_asU8());
+}
+
+/**
+ * Generates a new key for the specified keyTemplate using the
+ * KeyManager determined by typeUrl field of the keyTemplate.
+ *
+ *
+ *
+ * @return returns a key proto
+ */
+export async function newKey(keyTemplate: PbKeyTemplate): Promise<PbMessage> {
+ const manager = getKeyManagerWithNewKeyAllowedCheck_(keyTemplate);
+ return manager.getKeyFactory().newKey(keyTemplate.getValue_asU8());
+}
+
+/**
+ * Convenience method for extracting the public key data from the private key
+ * given by serializedPrivateKey.
+ * It looks up a KeyManager identified by typeUrl, which must hold
+ * PrivateKeyFactory, and calls getPublicKeyData method of that factory.
+ *
+ */
+export function getPublicKeyData(
+ typeUrl: string, serializedPrivateKey: Uint8Array): PbKeyData {
+ const manager = getKeyManager(typeUrl);
+
+ // This solution might cause some problems in the future due to Closure
+ // compiler optimizations, which may map factory.getPublicKeyData to
+ // concrete function.
+ const factory = (manager.getKeyFactory() as AnyDuringMigration);
+ if (!factory.getPublicKeyData) {
+ throw new SecurityException(
+ 'Key manager for key type ' + typeUrl +
+ ' does not have a private key factory.');
+ }
+ return factory.getPublicKeyData(serializedPrivateKey);
+}
+
+/**
+ * Resets the registry.
+ * After reset the registry is empty, i.e. it contains no key managers.
+ *
+ * This method is only for testing.
+ */
+export function reset() {
+ typeToManagerMap_.clear();
+ typeToNewKeyAllowedMap_.clear();
+ primitiveTypeToWrapper_.clear();
+}
+
+/**
+ * It finds a KeyManager given by keyTemplate.typeUrl and returns it if it
+ * allows creating new keys.
+ *
+ *
+ */
+function getKeyManagerWithNewKeyAllowedCheck_(keyTemplate: PbKeyTemplate):
+ KeyManager.KeyManager<AnyDuringMigration> {
+ const keyType = keyTemplate.getTypeUrl();
+ const manager = getKeyManager(keyType);
+ if (!typeToNewKeyAllowedMap_.get(keyType)) {
+ throw new SecurityException(
+ 'New key operation is forbidden for ' +
+ 'key type: ' + keyType + '.');
+ }
+ return manager;
+}
+
+/**
+ * Tries to register a primitive wrapper.
+ */
+export function registerPrimitiveWrapper<P>(wrapper: PrimitiveWrapper<P>) {
+ if (!wrapper) {
+ throw new SecurityException('primitive wrapper cannot be null');
+ }
+ const primitiveType = wrapper.getPrimitiveType();
+ if (!primitiveType) {
+ throw new SecurityException('primitive wrapper cannot be undefined');
+ }
+ if (primitiveTypeToWrapper_.has(primitiveType)) {
+ // Cannot overwrite the existing key manager by a new one.
+ if (!(primitiveTypeToWrapper_.get(primitiveType) instanceof
+ wrapper.constructor)) {
+ throw new SecurityException(
+ 'primitive wrapper for type ' + primitiveType +
+ ' has already been registered and cannot be overwritten');
+ }
+ }
+ primitiveTypeToWrapper_.set(primitiveType, wrapper);
+}
+
+/**
+ * Wraps a PrimitiveSet and returns a single instance.
+ */
+export function wrap<P>(primitiveSet: PrimitiveSet.PrimitiveSet<P>): P {
+ if (!primitiveSet) {
+ throw new SecurityException('primitive set cannot be null.');
+ }
+ const primitiveType = primitiveSet.getPrimitiveType();
+ const wrapper = primitiveTypeToWrapper_.get(primitiveType);
+ if (!wrapper) {
+ throw new SecurityException(
+ 'no primitive wrapper found for type ' + primitiveType);
+ }
+ return wrapper.wrap(primitiveSet);
+}
diff --git a/javascript/registry_test.js b/javascript/internal/registry_test.js
similarity index 98%
rename from javascript/registry_test.js
rename to javascript/internal/registry_test.js
index 6868bee..a7bf595 100644
--- a/javascript/registry_test.js
+++ b/javascript/internal/registry_test.js
@@ -19,14 +19,14 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
const AesCtrHmacAeadKeyManager = goog.require('tink.aead.AesCtrHmacAeadKeyManager');
-const EncryptThenAuthenticate = goog.require('tink.subtle.EncryptThenAuthenticate');
+const {EncryptThenAuthenticate} = goog.require('google3.third_party.tink.javascript.subtle.encrypt_then_authenticate');
const HybridConfig = goog.require('tink.hybrid.HybridConfig');
const HybridKeyTemplates = goog.require('tink.hybrid.HybridKeyTemplates');
-const KeyManager = goog.require('tink.KeyManager');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
-const Registry = goog.require('tink.Registry');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
const {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesCtrKey, PbAesCtrKeyFormat, PbAesCtrParams, PbEciesAeadHkdfPrivateKey, PbEciesAeadHkdfPublicKey, PbHashType, PbHmacKeyFormat, PbHmacParams, PbKeyData, PbKeyTemplate, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/util.js b/javascript/internal/util.ts
similarity index 68%
rename from javascript/util.js
rename to javascript/internal/util.ts
index 0f0bf0d..f90df1e 100644
--- a/javascript/util.js
+++ b/javascript/internal/util.ts
@@ -11,48 +11,51 @@
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+import * as Bytes from '../subtle/bytes';
+import * as EllipticCurves from '../subtle/elliptic_curves';
-goog.module('tink.Util');
+import {PbEllipticCurveType, PbHashType, PbKeyset, PbKeyStatusType, PbOutputPrefixType, PbPointFormat} from './proto';
-const Bytes = goog.require('tink.subtle.Bytes');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const {PbEllipticCurveType, PbHashType, PbKeyStatusType, PbKeyset, PbOutputPrefixType, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
+/**
+ * A type representing the constructor function for a given class. Unlike
+ * TypeScript's built-in `new` types, this works with abstract classes. It is
+ * used to describe the relationship between a primitive type object and its
+ * instances.
+ */
+export type Constructor<T> = Function&{prototype: T};
/**
* Validates the given key and throws SecurityException if it is invalid.
*
- * @param {!PbKeyset.Key} key
*/
-const validateKey = function(key) {
+export function validateKey(key: PbKeyset.Key) {
if (!key) {
throw new SecurityException('Key should be non null.');
}
if (!key.getKeyData()) {
- throw new SecurityException('Key data are missing for key '
- + key.getKeyId() + '.');
+ throw new SecurityException(
+ 'Key data are missing for key ' + key.getKeyId() + '.');
}
if (key.getOutputPrefixType() === PbOutputPrefixType.UNKNOWN_PREFIX) {
- throw new SecurityException('Key ' + key.getKeyId() +
- ' has unknown output prefix type.');
+ throw new SecurityException(
+ 'Key ' + key.getKeyId() + ' has unknown output prefix type.');
}
if (key.getStatus() === PbKeyStatusType.UNKNOWN_STATUS) {
- throw new SecurityException('Key ' + key.getKeyId() +
- ' has unknown status.');
+ throw new SecurityException(
+ 'Key ' + key.getKeyId() + ' has unknown status.');
}
-};
+}
/**
* Validates the given keyset and throws SecurityException if it is invalid.
*
- * @param {!PbKeyset} keyset
*/
-const validateKeyset = function(keyset) {
+export function validateKeyset(keyset: PbKeyset) {
if (!keyset || !keyset.getKeyList() || keyset.getKeyList().length < 1) {
throw new SecurityException(
'Keyset should be non null and must contain at least one key.');
}
-
let hasPrimary = false;
const numberOfKeys = keyset.getKeyList().length;
for (let i = 0; i < numberOfKeys; i++) {
@@ -66,12 +69,12 @@
hasPrimary = true;
}
}
-
if (!hasPrimary) {
- throw new SecurityException('Primary key has to be in the keyset and ' +
+ throw new SecurityException(
+ 'Primary key has to be in the keyset and ' +
'has to be enabled.');
}
-};
+}
// Functions which are useful for implementation of
// private and public EC keys.
@@ -83,11 +86,9 @@
* keyValue values in proto might either have some leading zeros or the leading
* zeros might be missing.
*
- * @param {!Uint8Array} bigEndianNumber
- * @param {number} sizeInBytes
- * @return {!Uint8Array}
*/
-const bigEndianNumberToCorrectLength = function(bigEndianNumber, sizeInBytes) {
+export function bigEndianNumberToCorrectLength(
+ bigEndianNumber: Uint8Array, sizeInBytes: number): Uint8Array {
const numberLen = bigEndianNumber.length;
if (numberLen < sizeInBytes) {
const zeros = new Uint8Array(sizeInBytes - numberLen);
@@ -103,13 +104,10 @@
return bigEndianNumber.slice(numberLen - sizeInBytes, numberLen);
}
return bigEndianNumber;
-};
+}
-/**
- * @param {!PbEllipticCurveType} curveTypeProto
- * @return {!EllipticCurves.CurveType}
- */
-const curveTypeProtoToSubtle = function(curveTypeProto) {
+export function curveTypeProtoToSubtle(curveTypeProto: PbEllipticCurveType):
+ EllipticCurves.CurveType {
switch (curveTypeProto) {
case PbEllipticCurveType.NIST_P256:
return EllipticCurves.CurveType.P256;
@@ -120,13 +118,9 @@
default:
throw new SecurityException('Unknown curve type.');
}
-};
+}
-/**
- * @param {!PbHashType} hashTypeProto
- * @return {string}
- */
-const hashTypeProtoToString = function(hashTypeProto) {
+export function hashTypeProtoToString(hashTypeProto: PbHashType): string {
switch (hashTypeProto) {
case PbHashType.SHA1:
return 'SHA-1';
@@ -137,13 +131,10 @@
default:
throw new SecurityException('Unknown hash type.');
}
-};
+}
-/**
- * @param {!PbPointFormat} pointFormatProto
- * @return {!EllipticCurves.PointFormatType}
- */
-const pointFormatProtoToSubtle = function(pointFormatProto) {
+export function pointFormatProtoToSubtle(pointFormatProto: PbPointFormat):
+ EllipticCurves.PointFormatType {
switch (pointFormatProto) {
case PbPointFormat.UNCOMPRESSED:
return EllipticCurves.PointFormatType.UNCOMPRESSED;
@@ -154,13 +145,4 @@
default:
throw new SecurityException('Unknown point format.');
}
-};
-
-exports = {
- bigEndianNumberToCorrectLength,
- curveTypeProtoToSubtle,
- hashTypeProtoToString,
- pointFormatProtoToSubtle,
- validateKey,
- validateKeyset,
-};
+}
diff --git a/javascript/util_test.js b/javascript/internal/util_test.js
similarity index 97%
rename from javascript/util_test.js
rename to javascript/internal/util_test.js
index 41cc01c..5ba4984 100644
--- a/javascript/util_test.js
+++ b/javascript/internal/util_test.js
@@ -15,8 +15,8 @@
goog.module('tink.UtilTest');
goog.setTestOnly('tink.UtilTest');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Util = goog.require('tink.Util');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEllipticCurveType, PbHashType, PbKeyData, PbKeyStatusType, PbKeyset, PbOutputPrefixType, PbPointFormat} = goog.require('google3.third_party.tink.javascript.internal.proto');
////////////////////////////////////////////////////////////////////////////////
diff --git a/javascript/keyset_handle.ts b/javascript/keyset_handle.ts
index f88a41c..ca2322f 100644
--- a/javascript/keyset_handle.ts
+++ b/javascript/keyset_handle.ts
@@ -1 +1 @@
-export {default as KeysetHandle} from 'goog:tink.KeysetHandle'; // from //third_party/tink/javascript:keyset_handle_legacy
+export {generateNew, KeysetHandle} from './internal/keyset_handle';
diff --git a/javascript/keyset_handle_legacy.js b/javascript/keyset_handle_legacy.js
deleted file mode 100644
index 9349790..0000000
--- a/javascript/keyset_handle_legacy.js
+++ /dev/null
@@ -1,229 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.KeysetHandle');
-
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const KeyManager = goog.require('tink.KeyManager');
-const KeysetReader = goog.require('tink.KeysetReader');
-const KeysetWriter = goog.require('tink.KeysetWriter');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
-const {PbKeyMaterialType, PbKeyStatusType, PbKeyTemplate, PbKeyset} = goog.require('google3.third_party.tink.javascript.internal.proto');
-
-/**
- * Keyset handle provide abstracted access to Keysets, to limit the exposure of
- * actual protocol buffers that hold sensitive key material.
- *
- * @final
- */
-class KeysetHandle {
- /**
- * @param {!PbKeyset} keyset
- */
- constructor(keyset) {
- Util.validateKeyset(keyset);
-
- /** @const @private {!PbKeyset} */
- this.keyset_ = keyset;
- }
-
- /**
- * Creates a KeysetHandle from an encrypted keyset obtained via reader, using
- * masterKeyAead to decrypt the keyset.
- *
- * @param {!KeysetReader} reader
- * @param {!Aead} masterKeyAead
- *
- * @return {!Promise<!KeysetHandle>}
- */
- static async read(reader, masterKeyAead) {
- // TODO implement
- throw new SecurityException('KeysetHandle -- read: Not implemented yet.');
- }
-
- /**
- * Creates a KeysetHandle from a keyset, obtained via reader, which
- * must contain no secret key material.
- *
- * This can be used to load public keysets or envelope encryption keysets.
- * Users that need to load cleartext keysets can use CleartextKeysetHandle.
- *
- * @param {!KeysetReader} reader
- * @return {!KeysetHandle}
- */
- static readNoSecret(reader) {
- if (reader === null) {
- throw new SecurityException('Reader has to be non-null.');
- }
- const keyset = reader.read();
- const keyList = keyset.getKeyList();
- for (let key of keyList) {
- switch (key.getKeyData().getKeyMaterialType()) {
- case PbKeyMaterialType.ASYMMETRIC_PUBLIC: // fall through
- case PbKeyMaterialType.REMOTE:
- continue;
- }
- throw new SecurityException('Keyset contains secret key material.');
- }
- return new KeysetHandle(keyset);
- }
-
- /**
- * Returns a new KeysetHandle that contains a single new key generated
- * according to keyTemplate.
- *
- * @param {!PbKeyTemplate} keyTemplate
- *
- * @return {!Promise<!KeysetHandle>}
- */
- static async generateNew(keyTemplate) {
- // TODO(thaidn): move this to a key manager.
- const keyset = await KeysetHandle.generateNewKeyset_(keyTemplate);
- return new KeysetHandle(keyset);
- }
-
- /**
- * Generates a new Keyset that contains a single new key generated
- * according to keyTemplate.
- *
- * @param {!PbKeyTemplate} keyTemplate
- * @private
- * @return {!Promise<!PbKeyset>}
- */
- static async generateNewKeyset_(keyTemplate) {
- const key = new PbKeyset.Key()
- .setStatus(PbKeyStatusType.ENABLED)
- .setOutputPrefixType(keyTemplate.getOutputPrefixType());
- const keyId = KeysetHandle.generateNewKeyId_();
- key.setKeyId(keyId);
- const keyData = await Registry.newKeyData(keyTemplate);
- key.setKeyData(keyData);
- const keyset = new PbKeyset();
- keyset.addKey(key);
- keyset.setPrimaryKeyId(keyId);
- return keyset;
- }
-
- /**
- * Generates a new random key ID.
- *
- * @private
- * @return {number} The key ID.
- */
- static generateNewKeyId_() {
- const bytes = Random.randBytes(4);
- let value = 0;
- for (let i = 0; i < bytes.length; i++) {
- value += (bytes[i] & 0xFF) << (i * 8);
- }
- // Make sure the key ID is a positive integer smaller than 2^32.
- return Math.abs(value) % 2 ** 32;
- };
-
-
- /**
- * Returns a primitive that uses key material from this keyset handle. If
- * opt_customKeyManager is defined then the provided key manager is used to
- * instantiate primitives. Otherwise key manager from Registry is used.
- *
- * @template P
- *
- * @param {!Object} primitiveType
- * @param {?KeyManager.KeyManager<P>=} opt_customKeyManager
- *
- * @return {!Promise<!P>}
- */
- async getPrimitive(primitiveType, opt_customKeyManager) {
- if (!primitiveType) {
- throw new InvalidArgumentsException('primitive type must be non-null');
- }
- const primitiveSet =
- await this.getPrimitiveSet(primitiveType, opt_customKeyManager);
- return Registry.wrap(primitiveSet);
- }
-
- /**
- * Creates a set of primitives corresponding to the keys with status Enabled
- * in the given keysetHandle, assuming all the correspoding key managers are
- * present (keys with status different from Enabled are skipped). If provided
- * uses customKeyManager instead of registered key managers for keys supported
- * by the customKeyManager.
- *
- * @template P
- * @package Visible for testing.
- *
- * @param {!Object} primitiveType
- * @param {?KeyManager.KeyManager<P>=} opt_customKeyManager
- *
- * @return {!Promise.<!PrimitiveSet.PrimitiveSet<P>>}
- */
- async getPrimitiveSet(primitiveType, opt_customKeyManager) {
- const primitiveSet = new PrimitiveSet.PrimitiveSet(primitiveType);
- const keys = this.keyset_.getKeyList();
- const keysLength = keys.length;
- for (let i = 0; i < keysLength; i++) {
- const key = keys[i];
- if (key.getStatus() === PbKeyStatusType.ENABLED) {
- const keyData = key.getKeyData();
- if (!keyData) {
- throw new SecurityException('Key data has to be non null.');
- }
- let primitive;
- if (opt_customKeyManager &&
- opt_customKeyManager.getKeyType() === keyData.getTypeUrl()) {
- primitive =
- await opt_customKeyManager.getPrimitive(primitiveType, keyData);
- } else {
- primitive = await Registry.getPrimitive(primitiveType, keyData);
- }
- const entry = primitiveSet.addPrimitive(primitive, key);
- if (key.getKeyId() === this.keyset_.getPrimaryKeyId()) {
- primitiveSet.setPrimary(entry);
- }
- }
- }
- return primitiveSet;
- }
-
-
- /**
- * Encrypts the underlying keyset with the provided masterKeyAead wnd writes
- * the resulting encryptedKeyset to the given writer which must be non-null.
- *
- * @param {!KeysetWriter} writer
- * @param {!Aead} masterKeyAead
- *
- */
- async write(writer, masterKeyAead) {
- // TODO implement
- throw new SecurityException('KeysetHandle -- write: Not implemented yet.');
- }
-
- /**
- * Returns the keyset held by this KeysetHandle.
- *
- * @package
- * @return {!PbKeyset}
- */
- getKeyset() {
- return this.keyset_;
- }
-}
-
-exports = KeysetHandle;
diff --git a/javascript/mac/subtle/hmac.ts b/javascript/mac/subtle/hmac.ts
index fc863e4..5b7d1b5 100644
--- a/javascript/mac/subtle/hmac.ts
+++ b/javascript/mac/subtle/hmac.ts
@@ -1 +1 @@
-export {default as Hmac} from 'goog:tink.subtle.Hmac'; // from //third_party/tink/javascript/subtle:mac
+export {fromRawKey, Hmac} from '../../subtle/hmac';
diff --git a/javascript/mac/subtle/index.ts b/javascript/mac/subtle/index.ts
index 261f749..39f4d62 100644
--- a/javascript/mac/subtle/index.ts
+++ b/javascript/mac/subtle/index.ts
@@ -1 +1 @@
-export * from './hmac';
+export {fromRawKey as hmacFromRawKey, Hmac} from './hmac';
diff --git a/javascript/registry.js b/javascript/registry.js
deleted file mode 100644
index 6a8720c..0000000
--- a/javascript/registry.js
+++ /dev/null
@@ -1,297 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.Registry');
-
-const KeyManager = goog.require('tink.KeyManager');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const {PbKeyData, PbKeyTemplate, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
-
-/**
- * Registry for KeyManagers.
- *
- * Registry maps supported key types to corresponding KeyManager objects (i.e.
- * the KeyManagers which may instantiate the primitive corresponding to the
- * given key or generate new key of the given type). Keeping KeyManagers for all
- * primitives in a single Registry (rather than having a separate keyManager per
- * primitive) enables modular construction of compound primitives from "simple"
- * ones (e.g. AES-CTR-HMAC AEAD encryption from IND-CPA encryption and MAC).
- *
- * Regular users will not usually work with Registry directly, but via primitive
- * factories, which query Registry for the specific KeyManagers in the
- * background.
- *
- * @final
- */
-class Registry {
- /**
- * Register the given manager for the given key type. Manager must be
- * non-nullptr. New keys are allowed if not specified.
- *
- * @template P
- * @static
- *
- * @param {!KeyManager.KeyManager<P>} manager
- * @param {boolean=} opt_newKeyAllowed
- */
- static registerKeyManager(manager, opt_newKeyAllowed) {
- if (opt_newKeyAllowed === undefined) {
- opt_newKeyAllowed = true;
- }
- if (!manager) {
- throw new SecurityException('Key manager cannot be null.');
- }
- const typeUrl = manager.getKeyType();
-
- if (Registry.typeToManagerMap_.has(typeUrl)) {
- // Cannot overwrite the existing key manager by a new one.
- if (!(Registry.typeToManagerMap_.get(typeUrl) instanceof
- manager.constructor)) {
- throw new SecurityException(
- 'Key manager for key type ' + typeUrl +
- ' has already been registered and cannot be overwritten.');
- }
-
- // It is forbidden to change new_key_allowed from false to true.
- if (!(Registry.typeToNewKeyAllowedMap_.get(typeUrl)) &&
- opt_newKeyAllowed) {
- throw new SecurityException(
- 'Key manager for key type ' + typeUrl +
- ' has already been registered with forbidden new key operation.');
- }
- Registry.typeToNewKeyAllowedMap_.set(typeUrl, opt_newKeyAllowed);
- }
-
- Registry.typeToManagerMap_.set(typeUrl, manager);
- Registry.typeToNewKeyAllowedMap_.set(typeUrl, opt_newKeyAllowed);
- }
-
- /**
- * Returns a key manager for the given key type or throws an exception if no
- * such manager found.
- *
- * @template P
- * @static
- *
- * @param {string} typeUrl -- key type
- *
- * @return {!KeyManager.KeyManager<P>}
- */
- static getKeyManager(typeUrl) {
- const res = Registry.typeToManagerMap_.get(typeUrl);
- if (!res) {
- throw new SecurityException(
- 'Key manager for key type ' + typeUrl + ' has not been registered.');
- }
- return res;
- }
-
- /**
- * It finds KeyManager according to key type (which is either given by
- * PbKeyData or given by opt_typeUrl), than calls the corresponding
- * manager's getPrimitive method.
- *
- * Either key is of type PbKeyData or opt_typeUrl must be provided.
- *
- * @template P
- * @static
- *
- * @param {!Object} primitiveType
- * @param {!PbKeyData|!PbMessage} key -- key is either a proto of some key
- * or key data.
- * @param {?string=} opt_typeUrl -- key type
- *
- * @return {!Promise.<!P>}
- */
- static async getPrimitive(primitiveType, key, opt_typeUrl) {
- if (key instanceof PbKeyData) {
- if (opt_typeUrl && key.getTypeUrl() != opt_typeUrl) {
- throw new SecurityException(
- 'Key type is ' + opt_typeUrl + ', but it is expected to be ' +
- key.getTypeUrl() + ' or undefined.');
- }
- opt_typeUrl = key.getTypeUrl();
- }
-
- if (!opt_typeUrl) {
- throw new SecurityException('Key type has to be specified.');
- }
-
- const manager = Registry.getKeyManager(opt_typeUrl);
- return await manager.getPrimitive(primitiveType, key);
- }
-
- /**
- * Generates a new PbKeyData for the specified keyTemplate. It finds a
- * KeyManager given by keyTemplate.typeUrl and calls the newKeyData method of
- * that manager.
- *
- * @static
- *
- * @param {!PbKeyTemplate} keyTemplate
- *
- * @return {!Promise<!PbKeyData>}
- */
- static async newKeyData(keyTemplate) {
- const manager = Registry.getKeyManagerWithNewKeyAllowedCheck_(keyTemplate);
- return await manager.getKeyFactory().newKeyData(
- keyTemplate.getValue_asU8());
- }
-
- /**
- * Generates a new key for the specified keyTemplate using the
- * KeyManager determined by typeUrl field of the keyTemplate.
- *
- * @static
- *
- * @param {!PbKeyTemplate} keyTemplate
- *
- * @return {!Promise<!PbMessage>} returns a key proto
- */
- static async newKey(keyTemplate) {
- const manager = Registry.getKeyManagerWithNewKeyAllowedCheck_(keyTemplate);
- return await manager.getKeyFactory().newKey(keyTemplate.getValue_asU8());
- }
-
- /**
- * Convenience method for extracting the public key data from the private key
- * given by serializedPrivateKey.
- * It looks up a KeyManager identified by typeUrl, which must hold
- * PrivateKeyFactory, and calls getPublicKeyData method of that factory.
- *
- * @param {string} typeUrl
- * @param {!Uint8Array} serializedPrivateKey
- * @return {!PbKeyData}
- */
- static getPublicKeyData(typeUrl, serializedPrivateKey) {
- const manager = Registry.getKeyManager(typeUrl);
- // This solution might cause some problems in the future due to Closure
- // compiler optimizations, which may map factory.getPublicKeyData to
- // concrete function.
- const factory = /** @type{?} */ (manager.getKeyFactory());
- if (!factory.getPublicKeyData) {
- throw new SecurityException(
- 'Key manager for key type ' + typeUrl +
- ' does not have a private key factory.');
- }
- return factory.getPublicKeyData(serializedPrivateKey);
- }
-
- /**
- * Resets the registry.
- * After reset the registry is empty, i.e. it contains no key managers.
- *
- * This method is only for testing.
- *
- * @static
- */
- static reset() {
- Registry.typeToManagerMap_.clear();
- Registry.typeToNewKeyAllowedMap_.clear();
- Registry.primitiveTypeToWrapper_.clear();
- }
-
- /**
- * It finds a KeyManager given by keyTemplate.typeUrl and returns it if it
- * allows creating new keys.
- *
- * @private
- * @param {!PbKeyTemplate} keyTemplate
- *
- * @return {!KeyManager.KeyManager}
- */
- static getKeyManagerWithNewKeyAllowedCheck_(keyTemplate) {
- const keyType = keyTemplate.getTypeUrl();
- const manager = Registry.getKeyManager(keyType);
- if (!Registry.typeToNewKeyAllowedMap_.get(keyType)) {
- throw new SecurityException(
- 'New key operation is forbidden for ' +
- 'key type: ' + keyType + '.');
- }
-
- return manager;
- }
-
- /**
- * Tries to register a primitive wrapper.
- *
- * @template P
- * @static
- *
- * @param {!PrimitiveWrapper<P>} wrapper
- */
- static registerPrimitiveWrapper(wrapper) {
- if (!wrapper) {
- throw new SecurityException('primitive wrapper cannot be null');
- }
- const primitiveType = wrapper.getPrimitiveType();
- if (!primitiveType) {
- throw new SecurityException('primitive wrapper cannot be undefined');
- }
-
- if (Registry.primitiveTypeToWrapper_.has(primitiveType)) {
- // Cannot overwrite the existing key manager by a new one.
- if (!(Registry.primitiveTypeToWrapper_.get(primitiveType) instanceof
- wrapper.constructor)) {
- throw new SecurityException(
- 'primitive wrapper for type ' + primitiveType +
- ' has already been registered and cannot be overwritten');
- }
- }
-
- Registry.primitiveTypeToWrapper_.set(primitiveType, wrapper);
- }
-
- /**
- * Wraps a PrimitiveSet and returns a single instance.
- *
- * @template P
- * @static
- *
- * @param {!PrimitiveSet.PrimitiveSet<P>} primitiveSet
- * @return {!P}
- */
- static wrap(primitiveSet) {
- if (!primitiveSet) {
- throw new SecurityException('primitive set cannot be null.');
- }
- const primitiveType = primitiveSet.getPrimitiveType();
- const wrapper = Registry.primitiveTypeToWrapper_.get(primitiveType);
- if (!wrapper) {
- throw new SecurityException(
- 'no primitive wrapper found for type ' + primitiveType);
- }
- return wrapper.wrap(primitiveSet);
- }
-}
-// key managers maps
-/**
- * @static @private {!Map<string,!KeyManager.KeyManager>}
- *
- */
-Registry.typeToManagerMap_ = new Map();
-/**
- * @static @private {!Map<string,boolean>}
- */
-Registry.typeToNewKeyAllowedMap_ = new Map();
-
-// primitive wrappers map
-/**
- * @static @private {!Map<!Object,!PrimitiveWrapper>}
- */
-Registry.primitiveTypeToWrapper_ = new Map();
-
-exports = Registry;
diff --git a/javascript/signature/ecdsa_for_signing.ts b/javascript/signature/ecdsa_for_signing.ts
index e0da03d..4988bfc 100644
--- a/javascript/signature/ecdsa_for_signing.ts
+++ b/javascript/signature/ecdsa_for_signing.ts
@@ -1,7 +1,8 @@
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
import EcdsaPrivateKeyManager from 'goog:tink.signature.EcdsaPrivateKeyManager'; // from //third_party/tink/javascript/signature:ecdsa_key_managers
import SignatureKeyTemplates from 'goog:tink.signature.SignatureKeyTemplates'; // from //third_party/tink/javascript/signature:key_templates
+import * as Registry from '../internal/registry';
+
export function register() {
Registry.registerKeyManager(new EcdsaPrivateKeyManager());
}
diff --git a/javascript/signature/ecdsa_for_verifying.ts b/javascript/signature/ecdsa_for_verifying.ts
index dae92fd..7273791 100644
--- a/javascript/signature/ecdsa_for_verifying.ts
+++ b/javascript/signature/ecdsa_for_verifying.ts
@@ -1,6 +1,7 @@
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
import EcdsaPublicKeyManager from 'goog:tink.signature.EcdsaPublicKeyManager'; // from //third_party/tink/javascript/signature:ecdsa_key_managers
+import * as Registry from '../internal/registry';
+
export function register() {
Registry.registerKeyManager(new EcdsaPublicKeyManager());
}
diff --git a/javascript/signature/ecdsa_private_key_manager.js b/javascript/signature/ecdsa_private_key_manager.js
index 15478ab..dc32450 100644
--- a/javascript/signature/ecdsa_private_key_manager.js
+++ b/javascript/signature/ecdsa_private_key_manager.js
@@ -14,15 +14,15 @@
goog.module('tink.signature.EcdsaPrivateKeyManager');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const EcdsaPublicKeyManager = goog.require('tink.signature.EcdsaPublicKeyManager');
-const EcdsaSign = goog.require('tink.subtle.EcdsaSign');
+const ecdsaSign = goog.require('google3.third_party.tink.javascript.subtle.ecdsa_sign');
const EcdsaUtil = goog.require('tink.signature.EcdsaUtil');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const KeyManager = goog.require('tink.KeyManager');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEcdsaKeyFormat, PbEcdsaParams, PbEcdsaPrivateKey, PbEcdsaPublicKey, PbKeyData, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -189,12 +189,12 @@
keyProto, EcdsaPrivateKeyManager.VERSION_,
EcdsaPublicKeyManager.VERSION);
- const recepientPrivateKey = EcdsaUtil.getJsonWebKeyFromProto(keyProto);
+ const recipientPrivateKey = EcdsaUtil.getJsonWebKeyFromProto(keyProto);
const params =
/** @type {!PbEcdsaParams} */ (keyProto.getPublicKey().getParams());
const hash = Util.hashTypeProtoToString(params.getHashType());
const encoding = EcdsaUtil.encodingTypeProtoToEnum(params.getEncoding());
- return await EcdsaSign.newInstance(recepientPrivateKey, hash, encoding);
+ return await ecdsaSign.fromJsonWebKey(recipientPrivateKey, hash, encoding);
}
/** @override */
diff --git a/javascript/signature/ecdsa_private_key_manager_test.js b/javascript/signature/ecdsa_private_key_manager_test.js
index 0627414..b249bec 100644
--- a/javascript/signature/ecdsa_private_key_manager_test.js
+++ b/javascript/signature/ecdsa_private_key_manager_test.js
@@ -17,11 +17,11 @@
const EcdsaPrivateKeyManager = goog.require('tink.signature.EcdsaPrivateKeyManager');
const EcdsaPublicKeyManager = goog.require('tink.signature.EcdsaPublicKeyManager');
-const KeyManager = goog.require('tink.KeyManager');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const {PbEcdsaKeyFormat, PbEcdsaParams, PbEcdsaPrivateKey, PbEcdsaPublicKey, PbEcdsaSignatureEncoding, PbEllipticCurveType, PbHashType, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
const {assertExists, assertInstanceof} = goog.require('google3.third_party.tink.javascript.testing.internal.test_utils');
diff --git a/javascript/signature/ecdsa_public_key_manager.js b/javascript/signature/ecdsa_public_key_manager.js
index 551e235..829cd0f 100644
--- a/javascript/signature/ecdsa_public_key_manager.js
+++ b/javascript/signature/ecdsa_public_key_manager.js
@@ -15,11 +15,11 @@
goog.module('tink.signature.EcdsaPublicKeyManager');
const EcdsaUtil = goog.require('tink.signature.EcdsaUtil');
-const EcdsaVerify = goog.require('tink.subtle.EcdsaVerify');
-const KeyManager = goog.require('tink.KeyManager');
+const ecdsaVerify = goog.require('google3.third_party.tink.javascript.subtle.ecdsa_verify');
+const KeyManager = goog.require('google3.third_party.tink.javascript.internal.key_manager');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEcdsaParams, PbEcdsaPublicKey, PbKeyData, PbMessage} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
@@ -67,7 +67,7 @@
const params = /** @type{!PbEcdsaParams} */ (keyProto.getParams());
const hash = Util.hashTypeProtoToString(params.getHashType());
const encoding = EcdsaUtil.encodingTypeProtoToEnum(params.getEncoding());
- return await EcdsaVerify.newInstance(jwk, hash, encoding);
+ return await ecdsaVerify.fromJsonWebKey(jwk, hash, encoding);
}
/** @override */
diff --git a/javascript/signature/ecdsa_public_key_manager_test.js b/javascript/signature/ecdsa_public_key_manager_test.js
index 5c442f7..f63713b 100644
--- a/javascript/signature/ecdsa_public_key_manager_test.js
+++ b/javascript/signature/ecdsa_public_key_manager_test.js
@@ -15,13 +15,13 @@
goog.module('tink.signature.EcdsaPublicKeyManagerTest');
goog.setTestOnly('tink.signature.EcdsaPublicKeyManagerTest');
-const Bytes = goog.require('tink.subtle.Bytes');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
const EcdsaPublicKeyManager = goog.require('tink.signature.EcdsaPublicKeyManager');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
-const Registry = goog.require('tink.Registry');
-const Util = goog.require('tink.Util');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
const {PbEcdsaParams, PbEcdsaPublicKey, PbEcdsaSignatureEncoding, PbEllipticCurveType, PbHashType, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
const KEY_TYPE = 'type.googleapis.com/google.crypto.tink.EcdsaPublicKey';
diff --git a/javascript/signature/ecdsa_util.js b/javascript/signature/ecdsa_util.js
index 2041fa5..f67f0fd 100644
--- a/javascript/signature/ecdsa_util.js
+++ b/javascript/signature/ecdsa_util.js
@@ -14,10 +14,10 @@
goog.module('tink.signature.EcdsaUtil');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Util = goog.require('tink.Util');
-const Validators = goog.require('tink.subtle.Validators');
+const Util = goog.require('google3.third_party.tink.javascript.internal.util');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const {PbEcdsaKeyFormat, PbEcdsaParams, PbEcdsaPrivateKey, PbEcdsaPublicKey, PbEcdsaSignatureEncoding: PbEcdsaSignatureEncodingType} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
diff --git a/javascript/signature/public_key_sign_wrapper.js b/javascript/signature/public_key_sign_wrapper.js
index 40f52c0..774479b 100644
--- a/javascript/signature/public_key_sign_wrapper.js
+++ b/javascript/signature/public_key_sign_wrapper.js
@@ -14,12 +14,12 @@
goog.module('tink.signature.PublicKeySignWrapper');
-const Bytes = goog.require('tink.subtle.Bytes');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
/**
* @final
diff --git a/javascript/signature/public_key_sign_wrapper_test.js b/javascript/signature/public_key_sign_wrapper_test.js
index 06f27b4..45d046d 100644
--- a/javascript/signature/public_key_sign_wrapper_test.js
+++ b/javascript/signature/public_key_sign_wrapper_test.js
@@ -15,11 +15,11 @@
goog.module('tink.signature.PublicKeySignWrapperTest');
goog.setTestOnly('tink.signature.PublicKeySignWrapperTest');
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const PublicKeySignWrapper = goog.require('tink.signature.PublicKeySignWrapper');
-const Random = goog.require('tink.subtle.Random');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('public key sign wrapper test', function() {
diff --git a/javascript/signature/public_key_verify_wrapper.js b/javascript/signature/public_key_verify_wrapper.js
index 4c4b9c2..cf8b2d2 100644
--- a/javascript/signature/public_key_verify_wrapper.js
+++ b/javascript/signature/public_key_verify_wrapper.js
@@ -14,12 +14,12 @@
goog.module('tink.signature.PublicKeyVerifyWrapper');
-const CryptoFormat = goog.require('tink.CryptoFormat');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
-const PrimitiveWrapper = goog.require('tink.PrimitiveWrapper');
+const {CryptoFormat} = goog.require('google3.third_party.tink.javascript.internal.crypto_format');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
+const {PrimitiveWrapper} = goog.require('google3.third_party.tink.javascript.internal.primitive_wrapper');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const {PbKeyStatusType} = goog.require('google3.third_party.tink.javascript.internal.proto');
/**
diff --git a/javascript/signature/public_key_verify_wrapper_test.js b/javascript/signature/public_key_verify_wrapper_test.js
index f793a57..42fcb18 100644
--- a/javascript/signature/public_key_verify_wrapper_test.js
+++ b/javascript/signature/public_key_verify_wrapper_test.js
@@ -15,13 +15,13 @@
goog.module('tink.signature.PublicKeyVerifyWrapperTest');
goog.setTestOnly('tink.signature.PublicKeyVerifyWrapperTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const PrimitiveSet = goog.require('tink.PrimitiveSet');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const PrimitiveSet = goog.require('google3.third_party.tink.javascript.internal.primitive_set');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const PublicKeySignWrapper = goog.require('tink.signature.PublicKeySignWrapper');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
const PublicKeyVerifyWrapper = goog.require('tink.signature.PublicKeyVerifyWrapper');
-const Random = goog.require('tink.subtle.Random');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbKeyStatusType, PbKeysetKey, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
describe('public key verify wrapper test', function() {
diff --git a/javascript/signature/sign_wrapper.ts b/javascript/signature/sign_wrapper.ts
index 20baf89..75a1da1 100644
--- a/javascript/signature/sign_wrapper.ts
+++ b/javascript/signature/sign_wrapper.ts
@@ -1,6 +1,7 @@
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
import PublicKeySignWrapper from 'goog:tink.signature.PublicKeySignWrapper'; // from //third_party/tink/javascript/signature:wrappers
+import * as Registry from '../internal/registry';
+
export function register() {
Registry.registerPrimitiveWrapper(new PublicKeySignWrapper());
}
diff --git a/javascript/signature/signature_config.js b/javascript/signature/signature_config.js
index 3f987b2..93c7e0b 100644
--- a/javascript/signature/signature_config.js
+++ b/javascript/signature/signature_config.js
@@ -18,7 +18,7 @@
const EcdsaPublicKeyManager = goog.require('tink.signature.EcdsaPublicKeyManager');
const PublicKeySignWrapper = goog.require('tink.signature.PublicKeySignWrapper');
const PublicKeyVerifyWrapper = goog.require('tink.signature.PublicKeyVerifyWrapper');
-const Registry = goog.require('tink.Registry');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
// Static methods and constants for registering with the Registry all instances
// of key types for digital signature supported in a particular release of Tink.
diff --git a/javascript/signature/signature_config_test.js b/javascript/signature/signature_config_test.js
index 4f2cf57..c009f0f 100644
--- a/javascript/signature/signature_config_test.js
+++ b/javascript/signature/signature_config_test.js
@@ -17,11 +17,11 @@
const EcdsaPrivateKeyManager = goog.require('tink.signature.EcdsaPrivateKeyManager');
const EcdsaPublicKeyManager = goog.require('tink.signature.EcdsaPublicKeyManager');
-const KeysetHandle = goog.require('tink.KeysetHandle');
+const {KeysetHandle} = goog.require('google3.third_party.tink.javascript.internal.keyset_handle');
const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const SignatureConfig = goog.require('tink.signature.SignatureConfig');
const SignatureKeyTemplates = goog.require('tink.signature.SignatureKeyTemplates');
const {PbKeyData, PbKeyStatusType, PbKeyTemplate, PbKeyset, PbOutputPrefixType} = goog.require('google3.third_party.tink.javascript.internal.proto');
diff --git a/javascript/signature/subtle/index.ts b/javascript/signature/subtle/index.ts
index 8fbee8e..6f2dcd1 100644
--- a/javascript/signature/subtle/index.ts
+++ b/javascript/signature/subtle/index.ts
@@ -1,2 +1,2 @@
-export {default as EcdsaSign} from 'goog:tink.subtle.EcdsaSign'; // from //third_party/tink/javascript/subtle:signature
-export {EcdsaSignatureEncodingType, exportCryptoKey, generateKeyPair, importPrivateKey, importPublicKey} from 'goog:tink.subtle.EllipticCurves'; // from //third_party/tink/javascript/subtle
+export {EcdsaSign, fromJsonWebKey as ecdsaSignFromJsonWebKey} from '../../subtle/ecdsa_sign';
+export {EcdsaSignatureEncodingType, exportCryptoKey, generateKeyPair, importPrivateKey, importPublicKey} from '../../subtle/elliptic_curves';
diff --git a/javascript/signature/verify_wrapper.ts b/javascript/signature/verify_wrapper.ts
index d560268..5c8a01b 100644
--- a/javascript/signature/verify_wrapper.ts
+++ b/javascript/signature/verify_wrapper.ts
@@ -1,6 +1,7 @@
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
import PublicKeyVerifyWrapper from 'goog:tink.signature.PublicKeyVerifyWrapper'; // from //third_party/tink/javascript/signature:wrappers
+import * as Registry from '../internal/registry';
+
export function register() {
Registry.registerPrimitiveWrapper(new PublicKeyVerifyWrapper());
}
diff --git a/javascript/subtle/aes_ctr.js b/javascript/subtle/aes_ctr.js
deleted file mode 100644
index 514133f..0000000
--- a/javascript/subtle/aes_ctr.js
+++ /dev/null
@@ -1,113 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.AesCtr');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const IndCpaCipher = goog.require('tink.subtle.IndCpaCipher');
-const Random = goog.require('tink.subtle.Random');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * The minimum IV size.
- *
- * @const {number}
- */
-const MIN_IV_SIZE_IN_BYTES = 12;
-
-/**
- * AES block size.
- *
- * @const {number}
- */
-const AES_BLOCK_SIZE_IN_BYTES = 16;
-
-/**
- * Implementation of AES-CTR.
- *
- * @implements {IndCpaCipher}
- * @protected
- * @final
- */
-class AesCtr {
- /**
- * @param {!webCrypto.CryptoKey} key
- * @param {number} ivSize the size of the IV
- */
- constructor(key, ivSize) {
- /** @const @private {!webCrypto.CryptoKey} */
- this.key_ = key;
-
- /** @const @private {number} */
- this.ivSize_ = ivSize;
- }
-
- /**
- * @param {!Uint8Array} key
- * @param {number} ivSize the size of the IV, must be larger than or equal to
- * {@link MIN_IV_SIZE_IN_BYTES}
- * @return {!Promise.<!IndCpaCipher>}
- * @static
- */
- static async newInstance(key, ivSize) {
- if (!Number.isInteger(ivSize)) {
- throw new SecurityException('invalid IV length, must be an integer');
- }
- if (ivSize < MIN_IV_SIZE_IN_BYTES || ivSize > AES_BLOCK_SIZE_IN_BYTES) {
- throw new SecurityException(
- 'invalid IV length, must be at least ' + MIN_IV_SIZE_IN_BYTES +
- ' and at most ' + AES_BLOCK_SIZE_IN_BYTES);
- }
- Validators.requireUint8Array(key);
- Validators.validateAesKeySize(key.length);
-
- const cryptoKey = await self.crypto.subtle.importKey(
- 'raw', key, {'name': 'AES-CTR', 'length': key.length}, false,
- ['encrypt', 'decrypt']);
-
- return new AesCtr(cryptoKey, ivSize);
- }
-
- /**
- * @override
- */
- async encrypt(plaintext) {
- Validators.requireUint8Array(plaintext);
- const iv = Random.randBytes(this.ivSize_);
- const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES);
- counter.set(iv);
- const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128};
- const ciphertext =
- await self.crypto.subtle.encrypt(alg, this.key_, plaintext);
- return Bytes.concat(iv, new Uint8Array(ciphertext));
- }
-
- /**
- * @override
- */
- async decrypt(ciphertext) {
- Validators.requireUint8Array(ciphertext);
- if (ciphertext.length < this.ivSize_) {
- throw new SecurityException('ciphertext too short');
- }
- const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES);
- counter.set(ciphertext.subarray(0, this.ivSize_));
- const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128};
- return new Uint8Array(await self.crypto.subtle.decrypt(
- alg, this.key_, new Uint8Array(ciphertext.subarray(this.ivSize_))));
- }
-}
-
-exports = AesCtr;
diff --git a/javascript/subtle/aes_ctr.ts b/javascript/subtle/aes_ctr.ts
new file mode 100644
index 0000000..68a6a4a
--- /dev/null
+++ b/javascript/subtle/aes_ctr.ts
@@ -0,0 +1,92 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+
+import * as Bytes from './bytes';
+import {IndCpaCipher} from './ind_cpa_cipher';
+import * as Random from './random';
+import * as Validators from './validators';
+
+/**
+ * The minimum IV size.
+ *
+ */
+const MIN_IV_SIZE_IN_BYTES: number = 12;
+
+/**
+ * AES block size.
+ *
+ */
+const AES_BLOCK_SIZE_IN_BYTES: number = 16;
+
+/**
+ * Implementation of AES-CTR.
+ *
+ * @final
+ */
+export class AesCtr implements IndCpaCipher {
+ /**
+ * @param ivSize the size of the IV
+ */
+ constructor(
+ private readonly key: CryptoKey, private readonly ivSize: number) {}
+
+ /**
+ * @override
+ */
+ async encrypt(plaintext: Uint8Array): Promise<Uint8Array> {
+ Validators.requireUint8Array(plaintext);
+ const iv = Random.randBytes(this.ivSize);
+ const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES);
+ counter.set(iv);
+ const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128};
+ const ciphertext =
+ await self.crypto.subtle.encrypt(alg, this.key, plaintext);
+ return Bytes.concat(iv, new Uint8Array(ciphertext));
+ }
+
+ /**
+ * @override
+ */
+ async decrypt(ciphertext: Uint8Array): Promise<Uint8Array> {
+ Validators.requireUint8Array(ciphertext);
+ if (ciphertext.length < this.ivSize) {
+ throw new SecurityException('ciphertext too short');
+ }
+ const counter = new Uint8Array(AES_BLOCK_SIZE_IN_BYTES);
+ counter.set(ciphertext.subarray(0, this.ivSize));
+ const alg = {'name': 'AES-CTR', 'counter': counter, 'length': 128};
+ return new Uint8Array(await self.crypto.subtle.decrypt(
+ alg, this.key, new Uint8Array(ciphertext.subarray(this.ivSize))));
+ }
+}
+
+/**
+ * @param ivSize the size of the IV, must be larger than or equal to
+ * {@link MIN_IV_SIZE_IN_BYTES}
+ */
+export async function fromRawKey(
+ key: Uint8Array, ivSize: number): Promise<IndCpaCipher> {
+ if (!Number.isInteger(ivSize)) {
+ throw new SecurityException('invalid IV length, must be an integer');
+ }
+ if (ivSize < MIN_IV_SIZE_IN_BYTES || ivSize > AES_BLOCK_SIZE_IN_BYTES) {
+ throw new SecurityException(
+ 'invalid IV length, must be at least ' + MIN_IV_SIZE_IN_BYTES +
+ ' and at most ' + AES_BLOCK_SIZE_IN_BYTES);
+ }
+ Validators.requireUint8Array(key);
+ Validators.validateAesKeySize(key.length);
+ const cryptoKey = await self.crypto.subtle.importKey(
+ 'raw', key, {'name': 'AES-CTR', 'length': key.length}, false,
+ ['encrypt', 'decrypt']);
+ return new AesCtr(cryptoKey, ivSize);
+}
diff --git a/javascript/subtle/aes_ctr_test.js b/javascript/subtle/aes_ctr_test.js
index 52dbcc1..eddccb2 100644
--- a/javascript/subtle/aes_ctr_test.js
+++ b/javascript/subtle/aes_ctr_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.AesCtrTest');
goog.setTestOnly('tink.subtle.AesCtrTest');
-const AesCtr = goog.require('tink.subtle.AesCtr');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {fromRawKey: aesCtrFromRawKey} = goog.require('google3.third_party.tink.javascript.subtle.aes_ctr');
describe('aes ctr test', function() {
beforeEach(function() {
@@ -36,7 +36,7 @@
const key = Random.randBytes(16);
for (let i = 0; i < 100; i++) {
const msg = Random.randBytes(20);
- const cipher = await AesCtr.newInstance(key, 16);
+ const cipher = await aesCtrFromRawKey(key, 16);
let ciphertext = await cipher.encrypt(msg);
let plaintext = await cipher.decrypt(ciphertext);
expect(Bytes.toHex(plaintext)).toBe(Bytes.toHex(msg));
@@ -44,7 +44,7 @@
});
it('probabilistic encryption', async function() {
- const cipher = await AesCtr.newInstance(Random.randBytes(16), 16);
+ const cipher = await aesCtrFromRawKey(Random.randBytes(16), 16);
const msg = Random.randBytes(20);
const results = new Set();
for (let i = 0; i < 100; i++) {
@@ -56,7 +56,7 @@
it('constructor', async function() {
try {
- await AesCtr.newInstance(Random.randBytes(16), 11); // IV size too short
+ await aesCtrFromRawKey(Random.randBytes(16), 11); // IV size too short
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -64,7 +64,7 @@
'SecurityException: invalid IV length, must be at least 12 and at most 16');
}
try {
- await AesCtr.newInstance(Random.randBytes(16), 17); // IV size too long
+ await aesCtrFromRawKey(Random.randBytes(16), 17); // IV size too long
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -72,7 +72,7 @@
'SecurityException: invalid IV length, must be at least 12 and at most 16');
}
try {
- await AesCtr.newInstance(
+ await aesCtrFromRawKey(
Random.randBytes(24), 12); // 192-bit keys not supported
fail('Should throw an exception.');
} catch (e) {
@@ -83,7 +83,7 @@
it('constructor, invalid iv sizes', async function() {
try {
- await AesCtr.newInstance(Random.randBytes(16), NaN);
+ await aesCtrFromRawKey(Random.randBytes(16), NaN);
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -91,7 +91,7 @@
}
try {
- await AesCtr.newInstance(Random.randBytes(16), 12.5);
+ await aesCtrFromRawKey(Random.randBytes(16), 12.5);
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -99,7 +99,7 @@
}
try {
- await AesCtr.newInstance(Random.randBytes(16), 0);
+ await aesCtrFromRawKey(Random.randBytes(16), 0);
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -128,7 +128,7 @@
const iv = Bytes.fromHex(testVector['iv']);
const msg = Bytes.fromHex(testVector['message']);
const ciphertext = Bytes.fromHex(testVector['ciphertext']);
- const aesctr = await AesCtr.newInstance(key, iv.length);
+ const aesctr = await aesCtrFromRawKey(key, iv.length);
const plaintext = await aesctr.decrypt(Bytes.concat(iv, ciphertext));
expect(Bytes.toHex(plaintext)).toBe(Bytes.toHex(msg));
}
diff --git a/javascript/subtle/aes_gcm.js b/javascript/subtle/aes_gcm.js
deleted file mode 100644
index db6cf11..0000000
--- a/javascript/subtle/aes_gcm.js
+++ /dev/null
@@ -1,122 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.AesGcm');
-
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Random = goog.require('tink.subtle.Random');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * The only supported IV size.
- *
- * @const {number}
- */
-const IV_SIZE_IN_BYTES = 12;
-
-/**
- * The only supported tag size.
- *
- * @const {number}
- */
-const TAG_SIZE_IN_BITS = 128;
-
-/**
- * Implementation of AES-GCM.
- *
- * @public
- * @final
- */
-class AesGcm extends Aead {
- /**
- * @param {!webCrypto.CryptoKey} key
- */
- constructor(key) {
- super();
- /** @const @private {!webCrypto.CryptoKey} */
- this.key_ = key;
- }
-
- /**
- * @param {!Uint8Array} key
- * @return {!Promise.<!Aead>}
- * @static
- */
- static async newInstance(key) {
- Validators.requireUint8Array(key);
- Validators.validateAesKeySize(key.length);
-
- const webCryptoKey = await self.crypto.subtle.importKey(
- 'raw' /* format */, key /* keyData */,
- {'name': 'AES-GCM', 'length': key.length} /* algo */,
- false /* extractable*/, ['encrypt', 'decrypt'] /* usage */);
- return new AesGcm(webCryptoKey);
- }
-
- /**
- * @override
- */
- async encrypt(plaintext, opt_associatedData) {
- Validators.requireUint8Array(plaintext);
- if (opt_associatedData != null) {
- Validators.requireUint8Array(opt_associatedData);
- }
- const iv = Random.randBytes(IV_SIZE_IN_BYTES);
- const alg = {
- 'name': 'AES-GCM',
- 'iv': iv,
- 'tagLength': TAG_SIZE_IN_BITS,
- };
- if (opt_associatedData) {
- alg['additionalData'] = opt_associatedData;
- }
- const ciphertext =
- await self.crypto.subtle.encrypt(alg, this.key_, plaintext);
- return Bytes.concat(iv, new Uint8Array(ciphertext));
- }
-
- /**
- * @override
- */
- async decrypt(ciphertext, opt_associatedData) {
- Validators.requireUint8Array(ciphertext);
- if (ciphertext.length < IV_SIZE_IN_BYTES + TAG_SIZE_IN_BITS / 8) {
- throw new SecurityException('ciphertext too short');
- }
- if (opt_associatedData != null) {
- Validators.requireUint8Array(opt_associatedData);
- }
- const iv = new Uint8Array(IV_SIZE_IN_BYTES);
- iv.set(ciphertext.subarray(0, IV_SIZE_IN_BYTES));
- const alg = {
- 'name': 'AES-GCM',
- 'iv': iv,
- 'tagLength': TAG_SIZE_IN_BITS,
- };
- if (opt_associatedData) {
- alg['additionalData'] = opt_associatedData;
- }
- try {
- return new Uint8Array(await self.crypto.subtle.decrypt(
- alg, this.key_,
- new Uint8Array(ciphertext.subarray(IV_SIZE_IN_BYTES))));
- } catch (e) {
- throw new SecurityException(e.toString());
- }
- }
-}
-
-exports = AesGcm;
diff --git a/javascript/subtle/aes_gcm.ts b/javascript/subtle/aes_gcm.ts
new file mode 100644
index 0000000..4e53f58
--- /dev/null
+++ b/javascript/subtle/aes_gcm.ts
@@ -0,0 +1,108 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {Aead} from '../aead/internal/aead';
+import {SecurityException} from '../exception/security_exception';
+
+import * as Bytes from './bytes';
+import * as Random from './random';
+import * as Validators from './validators';
+
+/**
+ * The only supported IV size.
+ *
+ */
+const IV_SIZE_IN_BYTES: number = 12;
+
+/**
+ * The only supported tag size.
+ *
+ */
+const TAG_SIZE_IN_BITS: number = 128;
+
+/**
+ * Implementation of AES-GCM.
+ *
+ * @final
+ */
+export class AesGcm implements Aead {
+ constructor(private readonly key: CryptoKey) {}
+
+ /**
+ * @override
+ */
+ async encrypt(plaintext: Uint8Array, associatedData?: Uint8Array):
+ Promise<Uint8Array> {
+ Validators.requireUint8Array(plaintext);
+ if (associatedData != null) {
+ Validators.requireUint8Array(associatedData);
+ }
+ const iv = Random.randBytes(IV_SIZE_IN_BYTES);
+ const alg: AesGcmParams = {
+ 'name': 'AES-GCM',
+ 'iv': iv,
+ 'tagLength': TAG_SIZE_IN_BITS
+ };
+ if (associatedData) {
+ alg['additionalData'] = associatedData;
+ }
+ const ciphertext =
+ await self.crypto.subtle.encrypt(alg, this.key, plaintext);
+ return Bytes.concat(iv, new Uint8Array(ciphertext));
+ }
+
+ /**
+ * @override
+ */
+ async decrypt(ciphertext: Uint8Array, associatedData?: Uint8Array):
+ Promise<Uint8Array> {
+ Validators.requireUint8Array(ciphertext);
+ if (ciphertext.length < IV_SIZE_IN_BYTES + TAG_SIZE_IN_BITS / 8) {
+ throw new SecurityException('ciphertext too short');
+ }
+ if (associatedData != null) {
+ Validators.requireUint8Array(associatedData);
+ }
+ const iv = new Uint8Array(IV_SIZE_IN_BYTES);
+ iv.set(ciphertext.subarray(0, IV_SIZE_IN_BYTES));
+ const alg: AesGcmParams = {
+ 'name': 'AES-GCM',
+ 'iv': iv,
+ 'tagLength': TAG_SIZE_IN_BITS
+ };
+ if (associatedData) {
+ alg['additionalData'] = associatedData;
+ }
+ try {
+ return new Uint8Array(await self.crypto.subtle.decrypt(
+ alg, this.key,
+ new Uint8Array(ciphertext.subarray(IV_SIZE_IN_BYTES))));
+ } catch (e) {
+ throw new SecurityException(e.toString());
+ }
+ }
+}
+
+export async function fromRawKey(key: Uint8Array): Promise<Aead> {
+ Validators.requireUint8Array(key);
+ Validators.validateAesKeySize(key.length);
+ const webCryptoKey = await self.crypto.subtle.importKey(
+ /* format */
+ 'raw', key,
+ /* keyData */
+ {'name': 'AES-GCM', 'length': key.length},
+ /* algo */
+ false,
+ /* extractable*/
+ ['encrypt', 'decrypt']);
+
+ /* usage */
+ return new AesGcm(webCryptoKey);
+}
diff --git a/javascript/subtle/aes_gcm_test.js b/javascript/subtle/aes_gcm_test.js
index 027ba30..0a7f6b4 100644
--- a/javascript/subtle/aes_gcm_test.js
+++ b/javascript/subtle/aes_gcm_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.AesGcmTest');
goog.setTestOnly('tink.subtle.AesGcmTest');
-const AesGcm = goog.require('tink.subtle.AesGcm');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {fromRawKey: aesGcmFromRawKey} = goog.require('google3.third_party.tink.javascript.subtle.aes_gcm');
/**
* Asserts that an exception is the result of a Web Crypto error.
@@ -41,7 +41,7 @@
});
it('basic', async function() {
- const aead = await AesGcm.newInstance(Random.randBytes(16));
+ const aead = await aesGcmFromRawKey(Random.randBytes(16));
for (let i = 0; i < 100; i++) {
const msg = Random.randBytes(i);
let ciphertext = await aead.encrypt(msg);
@@ -64,7 +64,7 @@
});
it('probabilistic encryption', async function() {
- const aead = await AesGcm.newInstance(Random.randBytes(16));
+ const aead = await aesGcmFromRawKey(Random.randBytes(16));
const msg = Random.randBytes(20);
const aad = Random.randBytes(20);
const results = new Set();
@@ -76,7 +76,7 @@
});
it('bit flip ciphertext', async function() {
- const aead = await AesGcm.newInstance(Random.randBytes(16));
+ const aead = await aesGcmFromRawKey(Random.randBytes(16));
const plaintext = Random.randBytes(8);
const aad = Random.randBytes(8);
const ciphertext = await aead.encrypt(plaintext, aad);
@@ -95,7 +95,7 @@
});
it('bit flip aad', async function() {
- const aead = await AesGcm.newInstance(Random.randBytes(16));
+ const aead = await aesGcmFromRawKey(Random.randBytes(16));
const plaintext = Random.randBytes(8);
const aad = Random.randBytes(8);
const ciphertext = await aead.encrypt(plaintext, aad);
@@ -114,7 +114,7 @@
});
it('truncation', async function() {
- const aead = await AesGcm.newInstance(Random.randBytes(16));
+ const aead = await aesGcmFromRawKey(Random.randBytes(16));
const plaintext = Random.randBytes(8);
const aad = Random.randBytes(8);
const ciphertext = await aead.encrypt(plaintext, aad);
@@ -626,7 +626,7 @@
];
for (let i = 0; i < NIST_TEST_VECTORS.length; i++) {
const testVector = NIST_TEST_VECTORS[i];
- const aead = await AesGcm.newInstance(Bytes.fromHex(testVector['Key']));
+ const aead = await aesGcmFromRawKey(Bytes.fromHex(testVector['Key']));
const ciphertext = Bytes.fromHex(
testVector['IV'] + testVector['CT'] + testVector['Tag']);
const aad = Bytes.fromHex(testVector['AAD']);
diff --git a/javascript/subtle/bytes.js b/javascript/subtle/bytes.ts
similarity index 61%
rename from javascript/subtle/bytes.js
rename to javascript/subtle/bytes.ts
index 51d997e..26b8912 100644
--- a/javascript/subtle/bytes.js
+++ b/javascript/subtle/bytes.ts
@@ -1,28 +1,22 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.Bytes');
-
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
/**
* Does near constant time byte array comparison.
- * @param {!Uint8Array} ba1 The first bytearray to check.
- * @param {!Uint8Array} ba2 The second bytearray to check.
- * @return {boolean} If the array are equal.
+ * @param ba1 The first bytearray to check.
+ * @param ba2 The second bytearray to check.
+ * @return If the array are equal.
*/
-const isEqual = function(ba1, ba2) {
+export function isEqual(ba1: Uint8Array, ba2: Uint8Array): boolean {
if (ba1.length !== ba2.length) {
return false;
}
@@ -31,36 +25,33 @@
result |= ba1[i] ^ ba2[i];
}
return result == 0;
-};
-
+}
/**
* Returns a new array that is the result of joining the arguments.
- * @param {...!Uint8Array} var_args
- * @return {!Uint8Array}
*/
-const concat = function(var_args) {
+export function concat(...var_args: Uint8Array[]): Uint8Array {
let length = 0;
for (let i = 0; i < arguments.length; i++) {
length += arguments[i].length;
}
- let result = new Uint8Array(length);
+ const result = new Uint8Array(length);
let curOffset = 0;
for (let i = 0; i < arguments.length; i++) {
result.set(arguments[i], curOffset);
curOffset += arguments[i].length;
}
return result;
-};
+}
/**
* Converts a non-negative integer number to a 64-bit big-endian byte array.
- * @param {number} value The number to convert.
- * @return {!Uint8Array} The number as a big-endian byte array.
+ * @param value The number to convert.
+ * @return The number as a big-endian byte array.
* @throws {InvalidArgumentsException}
* @static
*/
-const fromNumber = function(value) {
+export function fromNumber(value: number): Uint8Array {
if (isNaN(value) || value % 1 !== 0) {
throw new InvalidArgumentsException('cannot convert non-integer value');
}
@@ -71,135 +62,126 @@
throw new InvalidArgumentsException(
'cannot convert number larger than ' + Number.MAX_SAFE_INTEGER);
}
- const two_power_32 = 2**32;
- let low = value % two_power_32;
- let high = value / two_power_32;
+ const twoPower32 = 2 ** 32;
+ let low = value % twoPower32;
+ let high = value / twoPower32;
const result = new Uint8Array(8);
for (let i = 7; i >= 4; i--) {
- result[i] = low & 0xff;
+ result[i] = low & 255;
low >>>= 8;
}
for (let i = 3; i >= 0; i--) {
- result[i] = high & 0xff;
+ result[i] = high & 255;
high >>>= 8;
}
return result;
-};
+}
/**
* Converts the hex string to a byte array.
*
- * @param {string} hex the input
- * @return {!Uint8Array} the byte array output
+ * @param hex the input
+ * @return the byte array output
* @throws {!InvalidArgumentsException}
* @static
*/
-const fromHex = function(hex) {
+export function fromHex(hex: string): Uint8Array {
if (hex.length % 2 != 0) {
throw new InvalidArgumentsException(
'Hex string length must be multiple of 2');
}
- var arr = new Uint8Array(hex.length / 2);
- for (var i = 0; i < hex.length; i += 2) {
+ const arr = new Uint8Array(hex.length / 2);
+ for (let i = 0; i < hex.length; i += 2) {
arr[i / 2] = parseInt(hex.substring(i, i + 2), 16);
}
return arr;
-};
+}
/**
* Converts a byte array to hex.
*
- * @param {!Uint8Array} bytes the byte array input
- * @return {string} hex the output
+ * @param bytes the byte array input
+ * @return hex the output
* @static
*/
-const toHex = function(bytes) {
+export function toHex(bytes: Uint8Array): string {
let result = '';
for (let i = 0; i < bytes.length; i++) {
- let hexByte = bytes[i].toString(16);
+ const hexByte = bytes[i].toString(16);
result += hexByte.length > 1 ? hexByte : '0' + hexByte;
}
return result;
-};
+}
/**
* Converts the Base64 string to a byte array.
*
- * @param {string} encoded the base64 string
- * @param {boolean=} opt_webSafe True indicates we should use the alternative
+ * @param encoded the base64 string
+ * @param opt_webSafe True indicates we should use the alternative
* alphabet, which does not require escaping for use in URLs.
- * @return {!Uint8Array} the byte array output
+ * @return the byte array output
* @static
*/
-const fromBase64 = function(encoded, opt_webSafe) {
+export function fromBase64(encoded: string, opt_webSafe?: boolean): Uint8Array {
if (opt_webSafe) {
const normalBase64 = encoded.replace(/-/g, '+').replace(/_/g, '/');
return fromByteString(window.atob(normalBase64));
}
return fromByteString(window.atob(encoded));
-};
+}
/**
* Base64 encode a byte array.
*
- * @param {!Uint8Array} bytes the byte array input
- * @param {boolean=} opt_webSafe True indicates we should use the alternative
+ * @param bytes the byte array input
+ * @param opt_webSafe True indicates we should use the alternative
* alphabet, which does not require escaping for use in URLs.
- * @return {string} base64 output
+ * @return base64 output
* @static
*/
-const toBase64 = function(bytes, opt_webSafe) {
- let encoded =
- window.btoa(toByteString(bytes)).replace(/=/g, '') /* padding */;
+export function toBase64(bytes: Uint8Array, opt_webSafe?: boolean): string {
+ const encoded = window
+ .btoa(
+ /* padding */
+ toByteString(bytes))
+ .replace(/=/g, '');
if (opt_webSafe) {
return encoded.replace(/\+/g, '-').replace(/\//g, '_');
}
return encoded;
-};
+}
/**
* Converts a byte string to a byte array. Only support ASCII and Latin-1
* strings, does not support multi-byte characters.
*
- * @param {string} str the input
- * @return {!Uint8Array} the byte array output
+ * @param str the input
+ * @return the byte array output
* @static
*/
-const fromByteString = function(str) {
- let output = [];
+export function fromByteString(str: string): Uint8Array {
+ const output = [];
let p = 0;
for (let i = 0; i < str.length; i++) {
- let c = str.charCodeAt(i);
+ const c = str.charCodeAt(i);
output[p++] = c;
}
return new Uint8Array(output);
-};
+}
/**
* Turns a byte array into the string given by the concatenation of the
* characters to which the numbers correspond. Each byte is corresponding to a
* character. Does not support multi-byte characters.
*
- * @param {!Uint8Array} bytes Array of numbers representing
+ * @param bytes Array of numbers representing
* characters.
- * @return {string} Stringification of the array.
+ * @return Stringification of the array.
*/
-const toByteString = function(bytes) {
- var str = '';
- for (var i = 0; i < bytes.length; i += 1) {
+export function toByteString(bytes: Uint8Array): string {
+ let str = '';
+ for (let i = 0; i < bytes.length; i += 1) {
str += String.fromCharCode(bytes[i]);
}
return str;
-};
-
-exports = {
- concat,
- fromBase64,
- fromHex,
- fromNumber,
- fromByteString,
- isEqual,
- toBase64,
- toHex,
- toByteString,
-};
+}
diff --git a/javascript/subtle/bytes_test.js b/javascript/subtle/bytes_test.js
index 6108f8f..5ab1f3b 100644
--- a/javascript/subtle/bytes_test.js
+++ b/javascript/subtle/bytes_test.js
@@ -15,8 +15,8 @@
goog.module('tink.subtle.BytesTest');
goog.setTestOnly('tink.subtle.BytesTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
describe('bytes test', function() {
it('concat', function() {
diff --git a/javascript/subtle/ecdsa_sign.js b/javascript/subtle/ecdsa_sign.js
deleted file mode 100644
index adeff35..0000000
--- a/javascript/subtle/ecdsa_sign.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EcdsaSign');
-
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {PublicKeySign} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_sign');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * Implementation of ECDSA signing.
- *
- * @public
- * @final
- */
-class EcdsaSign extends PublicKeySign {
- /**
- * @param {!webCrypto.CryptoKey} key
- * @param {string} hash
- * @param {?EllipticCurves.EcdsaSignatureEncodingType=} opt_encoding The
- * optional encoding of the signature. If absent, default is IEEE P1363.
- */
- constructor(key, hash, opt_encoding) {
- super();
-
- /** @const @private {!webCrypto.CryptoKey} */
- this.key_ = key;
-
- /** @const @private {string} */
- this.hash_ = hash;
-
- if (!opt_encoding) {
- opt_encoding = EllipticCurves.EcdsaSignatureEncodingType.IEEE_P1363;
- }
-
- /** @const @private {!EllipticCurves.EcdsaSignatureEncodingType} */
- this.encoding_ = opt_encoding;
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} jwk
- * @param {string} hash
- * @param {?EllipticCurves.EcdsaSignatureEncodingType=} opt_encoding The
- * optional encoding of the signature. If absent, default is IEEE P1363.
- *
- * @return {!Promise<!PublicKeySign>}
- * @static
- */
- static async newInstance(jwk, hash, opt_encoding) {
- if (!jwk) {
- throw new SecurityException('private key has to be non-null');
- }
- Validators.validateEcdsaParams(jwk.crv, hash);
- const cryptoKey = await EllipticCurves.importPrivateKey('ECDSA', jwk);
- return new EcdsaSign(cryptoKey, hash, opt_encoding);
- }
-
- /**
- * @override
- */
- async sign(data) {
- Validators.requireUint8Array(data);
- const signature = await window.crypto.subtle.sign(
- {
- name: 'ECDSA',
- hash: {
- name: this.hash_,
- },
- },
- this.key_, data);
-
- if (this.encoding_ == EllipticCurves.EcdsaSignatureEncodingType.DER) {
- return EllipticCurves.ecdsaIeee2Der(new Uint8Array(signature));
- }
- return new Uint8Array(signature);
- }
-}
-
-exports = EcdsaSign;
diff --git a/javascript/subtle/ecdsa_sign.ts b/javascript/subtle/ecdsa_sign.ts
new file mode 100644
index 0000000..fabdc1e
--- /dev/null
+++ b/javascript/subtle/ecdsa_sign.ts
@@ -0,0 +1,70 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+import {PublicKeySign} from '../signature/internal/public_key_sign';
+
+import * as EllipticCurves from './elliptic_curves';
+import * as Validators from './validators';
+
+/**
+ * Implementation of ECDSA signing.
+ *
+ * @final
+ */
+export class EcdsaSign implements PublicKeySign {
+ private readonly encoding_: EllipticCurves.EcdsaSignatureEncodingType;
+
+ /**
+ * @param opt_encoding The
+ * optional encoding of the signature. If absent, default is IEEE P1363.
+ */
+ constructor(
+ private readonly key: CryptoKey, private readonly hash: string,
+ opt_encoding?: EllipticCurves.EcdsaSignatureEncodingType|null) {
+ if (!opt_encoding) {
+ opt_encoding = EllipticCurves.EcdsaSignatureEncodingType.IEEE_P1363;
+ }
+ this.encoding_ = opt_encoding;
+ }
+
+ /**
+ * @override
+ */
+ async sign(message: Uint8Array): Promise<Uint8Array> {
+ Validators.requireUint8Array(message);
+ const signature = await window.crypto.subtle.sign(
+ {name: 'ECDSA', hash: {name: this.hash}}, this.key, message);
+ if (this.encoding_ == EllipticCurves.EcdsaSignatureEncodingType.DER) {
+ return EllipticCurves.ecdsaIeee2Der(new Uint8Array(signature));
+ }
+ return new Uint8Array(signature);
+ }
+}
+
+/**
+ * @param opt_encoding The
+ * optional encoding of the signature. If absent, default is IEEE P1363.
+ */
+export async function fromJsonWebKey(
+ jwk: JsonWebKey, hash: string,
+ opt_encoding?: EllipticCurves.EcdsaSignatureEncodingType|
+ null): Promise<PublicKeySign> {
+ if (!jwk) {
+ throw new SecurityException('private key has to be non-null');
+ }
+ const {crv} = jwk;
+ if (!crv) {
+ throw new SecurityException('curve has to be defined');
+ }
+ Validators.validateEcdsaParams(crv, hash);
+ const cryptoKey = await EllipticCurves.importPrivateKey('ECDSA', jwk);
+ return new EcdsaSign(cryptoKey, hash, opt_encoding);
+}
diff --git a/javascript/subtle/ecdsa_sign_test.js b/javascript/subtle/ecdsa_sign_test.js
index 6ee9d29..7b20968 100644
--- a/javascript/subtle/ecdsa_sign_test.js
+++ b/javascript/subtle/ecdsa_sign_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.EcdsaSignTest');
goog.setTestOnly('tink.subtle.EcdsaSignTest');
-const EcdsaSign = goog.require('tink.subtle.EcdsaSign');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {fromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecdsa_sign');
describe('ecdsa sign test', function() {
beforeEach(function() {
@@ -32,7 +32,7 @@
it('sign', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
for (let i = 0; i < 100; i++) {
const data = Random.randBytes(i);
@@ -51,7 +51,7 @@
it('sign with der encoding', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256',
EllipticCurves.EcdsaSignatureEncodingType.DER);
for (let i = 0; i < 100; i++) {
@@ -83,7 +83,7 @@
it('sign always generate new signatures', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
const signatures = new Set();
for (let i = 0; i < 100; i++) {
@@ -97,7 +97,7 @@
it('constructor with invalid hash', async function() {
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- await EcdsaSign.newInstance(
+ await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-1');
fail('Should throw an exception.');
} catch (e) {
@@ -109,7 +109,7 @@
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-384');
- await EcdsaSign.newInstance(
+ await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
@@ -120,7 +120,7 @@
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-521');
- await EcdsaSign.newInstance(
+ await fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
@@ -135,7 +135,7 @@
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
const jwk = await EllipticCurves.exportCryptoKey(keyPair.privateKey);
jwk.crv = 'blah';
- await EcdsaSign.newInstance(jwk, 'SHA-256');
+ await fromJsonWebKey(jwk, 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
expect(e.toString()).toBe('SecurityException: unsupported curve: blah');
diff --git a/javascript/subtle/ecdsa_verify.js b/javascript/subtle/ecdsa_verify.js
deleted file mode 100644
index 926703d..0000000
--- a/javascript/subtle/ecdsa_verify.js
+++ /dev/null
@@ -1,95 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EcdsaVerify');
-
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * Implementation of ECDSA verifying.
- *
- * @public
- * @final
- */
-class EcdsaVerify extends PublicKeyVerify {
- /**
- * @param {!webCrypto.CryptoKey} key
- * @param {string} hash
- * @param {!EllipticCurves.EcdsaSignatureEncodingType} encoding The
- * encoding of the signature.
- */
- constructor(key, hash, encoding) {
- super();
-
- /** @const @private {!webCrypto.CryptoKey} */
- this.key_ = key;
-
- /** @const @private {string} */
- this.hash_ = hash;
-
- /** @const @private {!EllipticCurves.EcdsaSignatureEncodingType} */
- this.encoding_ = encoding;
-
- /** @const @private {number} */
- this.ieeeSignatureLength_ = 2 *
- EllipticCurves.fieldSizeInBytes(
- EllipticCurves.curveFromString(key.algorithm['namedCurve']));
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} jwk
- * @param {string} hash
- * @param {?EllipticCurves.EcdsaSignatureEncodingType=} opt_encoding The
- * optional encoding of the signature. If absent, default is IEEE P1363.
- *
- * @return {!Promise<!PublicKeyVerify>}
- * @static
- */
- static async newInstance(jwk, hash, opt_encoding) {
- if (!jwk) {
- throw new SecurityException('public key has to be non-null');
- }
- Validators.validateEcdsaParams(jwk.crv, hash);
- const cryptoKey = await EllipticCurves.importPublicKey('ECDSA', jwk);
- if (!opt_encoding) {
- opt_encoding = EllipticCurves.EcdsaSignatureEncodingType.IEEE_P1363;
- }
- return new EcdsaVerify(cryptoKey, hash, opt_encoding);
- }
-
- /**
- * @override
- */
- async verify(signature, data) {
- Validators.requireUint8Array(signature);
- Validators.requireUint8Array(data);
- if (this.encoding_ == EllipticCurves.EcdsaSignatureEncodingType.DER) {
- signature =
- EllipticCurves.ecdsaDer2Ieee(signature, this.ieeeSignatureLength_);
- }
- return await window.crypto.subtle.verify(
- {
- name: 'ECDSA',
- hash: {
- name: this.hash_,
- },
- },
- this.key_, signature, data);
- }
-}
-
-exports = EcdsaVerify;
diff --git a/javascript/subtle/ecdsa_verify.ts b/javascript/subtle/ecdsa_verify.ts
new file mode 100644
index 0000000..08b9803
--- /dev/null
+++ b/javascript/subtle/ecdsa_verify.ts
@@ -0,0 +1,75 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+import {PublicKeyVerify} from '../signature/internal/public_key_verify';
+
+import * as EllipticCurves from './elliptic_curves';
+import * as Validators from './validators';
+
+/**
+ * Implementation of ECDSA verifying.
+ *
+ * @final
+ */
+export class EcdsaVerify implements PublicKeyVerify {
+ private readonly ieeeSignatureLength_: number;
+
+ /**
+ * @param encoding The
+ * encoding of the signature.
+ */
+ constructor(
+ private readonly key: CryptoKey, private readonly hash: string,
+ private readonly encoding: EllipticCurves.EcdsaSignatureEncodingType) {
+ const {namedCurve}: Partial<EcKeyAlgorithm> = key.algorithm;
+ if (!namedCurve) {
+ throw new SecurityException('Curve has to be defined.');
+ }
+ this.ieeeSignatureLength_ = 2 *
+ EllipticCurves.fieldSizeInBytes(
+ EllipticCurves.curveFromString(namedCurve));
+ }
+
+ /**
+ * @override
+ */
+ async verify(signature: Uint8Array, message: Uint8Array): Promise<boolean> {
+ Validators.requireUint8Array(signature);
+ Validators.requireUint8Array(message);
+ if (this.encoding === EllipticCurves.EcdsaSignatureEncodingType.DER) {
+ signature =
+ EllipticCurves.ecdsaDer2Ieee(signature, this.ieeeSignatureLength_);
+ }
+ return window.crypto.subtle.verify(
+ {name: 'ECDSA', hash: {name: this.hash}}, this.key, signature, message);
+ }
+}
+
+/**
+ * @param opt_encoding The
+ * optional encoding of the signature. If absent, default is IEEE P1363.
+ */
+export async function fromJsonWebKey(
+ jwk: JsonWebKey, hash: string,
+ encoding: EllipticCurves.EcdsaSignatureEncodingType =
+ EllipticCurves.EcdsaSignatureEncodingType.IEEE_P1363):
+ Promise<PublicKeyVerify> {
+ if (!jwk) {
+ throw new SecurityException('public key has to be non-null');
+ }
+ const {crv} = jwk;
+ if (!crv) {
+ throw new SecurityException('curve has to be defined');
+ }
+ Validators.validateEcdsaParams(crv, hash);
+ const cryptoKey = await EllipticCurves.importPublicKey('ECDSA', jwk);
+ return new EcdsaVerify(cryptoKey, hash, encoding);
+}
diff --git a/javascript/subtle/ecdsa_verify_test.js b/javascript/subtle/ecdsa_verify_test.js
index c8ed446..e3220cc 100644
--- a/javascript/subtle/ecdsa_verify_test.js
+++ b/javascript/subtle/ecdsa_verify_test.js
@@ -15,14 +15,14 @@
goog.module('tink.subtle.EcdsaVerifyTest');
goog.setTestOnly('tink.subtle.EcdsaVerifyTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EcdsaSign = goog.require('tink.subtle.EcdsaSign');
-const EcdsaVerify = goog.require('tink.subtle.EcdsaVerify');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
-const Random = goog.require('tink.subtle.Random');
-const Validators = goog.require('tink.subtle.Validators');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Validators = goog.require('google3.third_party.tink.javascript.subtle.validators');
const wycheproofEcdsaTestVectors = goog.require('tink.subtle.wycheproofEcdsaTestVectors');
+const ecdsaSign = goog.require('google3.third_party.tink.javascript.subtle.ecdsa_sign');
+const ecdsaVerify = goog.require('google3.third_party.tink.javascript.subtle.ecdsa_verify');
+const {PublicKeyVerify} = goog.require('google3.third_party.tink.javascript.signature.internal.public_key_verify');
describe('ecdsa verify test', function() {
beforeEach(function() {
@@ -37,9 +37,9 @@
it('verify', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await ecdsaSign.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
- const verifier = await EcdsaVerify.newInstance(
+ const verifier = await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
for (let i = 0; i < 100; i++) {
const data = Random.randBytes(i);
@@ -50,12 +50,12 @@
it('verify with der encoding', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await ecdsaSign.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256',
EllipticCurves.EcdsaSignatureEncodingType.DER);
- const verifier = await EcdsaVerify.newInstance(
+ const verifier = await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
- const verifierDer = await EcdsaVerify.newInstance(
+ const verifierDer = await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256',
EllipticCurves.EcdsaSignatureEncodingType.DER);
for (let i = 0; i < 100; i++) {
@@ -69,7 +69,7 @@
it('constructor with invalid hash', async function() {
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- await EcdsaVerify.newInstance(
+ await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-1');
fail('Should throw an exception.');
} catch (e) {
@@ -80,7 +80,7 @@
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-384');
- await EcdsaVerify.newInstance(
+ await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
@@ -91,7 +91,7 @@
try {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-521');
- await EcdsaVerify.newInstance(
+ await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
@@ -106,7 +106,7 @@
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
const jwk = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
jwk.crv = 'blah';
- await EcdsaVerify.newInstance(jwk, 'SHA-256');
+ await ecdsaVerify.fromJsonWebKey(jwk, 'SHA-256');
fail('Should throw an exception.');
} catch (e) {
expect(e.toString()).toBe('SecurityException: unsupported curve: blah');
@@ -115,9 +115,9 @@
it('verify modified signature', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await ecdsaSign.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
- const verifier = await EcdsaVerify.newInstance(
+ const verifier = await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
const data = Random.randBytes(20);
const signature = await signer.sign(data);
@@ -133,9 +133,9 @@
it('verify modified data', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDSA', 'P-256');
- const signer = await EcdsaSign.newInstance(
+ const signer = await ecdsaSign.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.privateKey), 'SHA-256');
- const verifier = await EcdsaVerify.newInstance(
+ const verifier = await ecdsaVerify.fromJsonWebKey(
await EllipticCurves.exportCryptoKey(keyPair.publicKey), 'SHA-256');
const data = Random.randBytes(20);
const signature = await signer.sign(data);
@@ -159,7 +159,7 @@
continue;
}
const verifier =
- await EcdsaVerify.newInstance(testGroup['jwk'], testGroup['sha']);
+ await ecdsaVerify.fromJsonWebKey(testGroup['jwk'], testGroup['sha']);
let errors = '';
for (let test of testGroup['tests']) {
errors += await runWycheproofTest(verifier, test);
diff --git a/javascript/subtle/ecies_aead_hkdf_dem_helper.js b/javascript/subtle/ecies_aead_hkdf_dem_helper.ts
similarity index 66%
rename from javascript/subtle/ecies_aead_hkdf_dem_helper.js
rename to javascript/subtle/ecies_aead_hkdf_dem_helper.ts
index d6bb7f7..4aacb40 100644
--- a/javascript/subtle/ecies_aead_hkdf_dem_helper.js
+++ b/javascript/subtle/ecies_aead_hkdf_dem_helper.ts
@@ -1,39 +1,30 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EciesAeadHkdfDemHelper');
-
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
+import {Aead} from '../aead/internal/aead';
/**
* A helper for DEM (data encapsulation mechanism) of ECIES-AEAD-HKDF.
- * @record
*/
-class EciesAeadHkdfDemHelper {
+export interface EciesAeadHkdfDemHelper {
/**
- * @return {number} the size of the DEM key in bytes
+ * @return the size of the DEM key in bytes
*/
- getDemKeySizeInBytes() {}
+ getDemKeySizeInBytes(): number;
/**
* Creates a new `Aead` primitive that uses the key material given in
* `demKey`, which must be of length `getDemKeySizeInBytes()`.
*
- * @param {!Uint8Array} demKey the DEM key.
- * @return {!Promise.<!Aead>} the newly created `Aead` primitive.
+ * @param demKey the DEM key.
+ * @return the newly created `Aead` primitive.
*/
- getAead(demKey) {}
+ getAead(demKey: Uint8Array): Promise<Aead>;
}
-
-exports = EciesAeadHkdfDemHelper;
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.js b/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.js
deleted file mode 100644
index 7f4e04f..0000000
--- a/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.js
+++ /dev/null
@@ -1,158 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EciesAeadHkdfHybridDecrypt');
-
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const EciesAeadHkdfDemHelper = goog.require('tink.subtle.EciesAeadHkdfDemHelper');
-const EciesHkdfKemRecipient = goog.require('tink.subtle.EciesHkdfKemRecipient');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {HybridDecrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_decrypt');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
-/**
- * Implementation of ECIES AEAD HKDF hybrid decryption.
- *
- * @protected
- * @final
- */
-class EciesAeadHkdfHybridDecrypt extends HybridDecrypt {
- /**
- * @param {!webCrypto.JsonWebKey} recipientPrivateKey
- * @param {!EciesHkdfKemRecipient} kemRecipient
- * @param {string} hkdfHash the name of the HMAC algorithm, accepted names
- * are: SHA-1, SHA-256 and SHA-512.
- * @param {!EllipticCurves.PointFormatType} pointFormat
- * @param {!EciesAeadHkdfDemHelper} demHelper
- * @param {!Uint8Array=} opt_hkdfSalt
- */
- constructor(
- recipientPrivateKey, kemRecipient, hkdfHash, pointFormat, demHelper,
- opt_hkdfSalt) {
- super();
-
- if (!recipientPrivateKey) {
- throw new SecurityException('Recipient private key has to be non-null.');
- }
- if (!kemRecipient) {
- throw new SecurityException('KEM recipient has to be non-null.');
- }
- if (!hkdfHash) {
- throw new SecurityException('HKDF hash algorithm has to be non-null.');
- }
- if (!pointFormat) {
- throw new SecurityException('Point format has to be non-null.');
- }
- if (!demHelper) {
- throw new SecurityException('DEM helper has to be non-null.');
- }
-
- const curveType =
- EllipticCurves.curveFromString(recipientPrivateKey['crv']);
- const headerSize =
- EllipticCurves.encodingSizeInBytes(curveType, pointFormat);
-
- /** @private @const {!EciesHkdfKemRecipient} */
- this.kemRecipient_ = kemRecipient;
- /** @private @const {string} */
- this.hkdfHash_ = hkdfHash;
- /** @private @const {!EllipticCurves.PointFormatType} */
- this.pointFormat_ = pointFormat;
- /** @private @const {!EciesAeadHkdfDemHelper} */
- this.demHelper_ = demHelper;
- /** @private @const {number} */
- this.headerSize_ = headerSize;
- /** @private @const {!Uint8Array|undefined} */
- this.hkdfSalt_ = opt_hkdfSalt;
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} recipientPrivateKey
- * @param {string} hkdfHash the name of the HMAC algorithm, accepted names
- * are: SHA-1, SHA-256 and SHA-512.
- * @param {!EllipticCurves.PointFormatType} pointFormat
- * @param {!EciesAeadHkdfDemHelper} demHelper
- * @param {!Uint8Array=} opt_hkdfSalt
- *
- * @return {!Promise.<!HybridDecrypt>}
- */
- static async newInstance(
- recipientPrivateKey, hkdfHash, pointFormat, demHelper, opt_hkdfSalt) {
- if (!recipientPrivateKey) {
- throw new SecurityException('Recipient private key has to be non-null.');
- }
- if (!hkdfHash) {
- throw new SecurityException('HKDF hash algorithm has to be non-null.');
- }
- if (!pointFormat) {
- throw new SecurityException('Point format has to be non-null.');
- }
- if (!demHelper) {
- throw new SecurityException('DEM helper has to be non-null.');
- }
-
- if (!recipientPrivateKey) {
- throw new SecurityException('Recipient private key has to be non-null.');
- }
- const kemRecipient =
- await EciesHkdfKemRecipient.newInstance(recipientPrivateKey);
-
- return new EciesAeadHkdfHybridDecrypt(
- recipientPrivateKey, kemRecipient, hkdfHash, pointFormat, demHelper,
- opt_hkdfSalt);
- }
-
- /**
- * Decrypts ciphertext using opt_contextInfo as info parameter of the
- * underlying HKDF.
- *
- * @override
- */
- async decrypt(ciphertext, opt_contextInfo) {
- if (ciphertext.length < this.headerSize_) {
- throw new SecurityException('Ciphertext is too short.');
- }
-
- // Split the ciphertext to KEM token and AEAD ciphertext.
- const kemToken = ciphertext.slice(0, this.headerSize_);
- const ciphertextBody =
- ciphertext.slice(this.headerSize_, ciphertext.length);
-
- const aead = await this.getAead_(kemToken, opt_contextInfo);
- return await aead.decrypt(ciphertextBody);
- }
-
- /**
- * @private
- * @param {!Uint8Array} kemToken
- * @param {?Uint8Array=} opt_contextInfo
- * @return {!Promise<!Aead>}
- */
- async getAead_(kemToken, opt_contextInfo) {
- // Variable hkdfInfo is not optional for decapsulate method. Thus it should
- // be an empty array in case that it is not defined by the caller of decrypt
- // method.
- if (!opt_contextInfo) {
- opt_contextInfo = new Uint8Array(0);
- }
-
- const symmetricKey = await this.kemRecipient_.decapsulate(
- kemToken, this.demHelper_.getDemKeySizeInBytes(), this.pointFormat_,
- this.hkdfHash_, opt_contextInfo, this.hkdfSalt_);
- return await this.demHelper_.getAead(symmetricKey);
- }
-}
-
-exports = EciesAeadHkdfHybridDecrypt;
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.ts b/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.ts
new file mode 100644
index 0000000..45b0015
--- /dev/null
+++ b/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt.ts
@@ -0,0 +1,132 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {Aead} from '../aead/internal/aead';
+import {SecurityException} from '../exception/security_exception';
+import {HybridDecrypt} from '../hybrid/internal/hybrid_decrypt';
+
+import {EciesAeadHkdfDemHelper} from './ecies_aead_hkdf_dem_helper';
+import {EciesHkdfKemRecipient, fromJsonWebKey as kemRecipientFromJsonWebKey} from './ecies_hkdf_kem_recipient';
+import * as EllipticCurves from './elliptic_curves';
+
+/**
+ * Implementation of ECIES AEAD HKDF hybrid decryption.
+ *
+ * @final
+ */
+export class EciesAeadHkdfHybridDecrypt implements HybridDecrypt {
+ private readonly kemRecipient_: EciesHkdfKemRecipient;
+ private readonly hkdfHash_: string;
+ private readonly pointFormat_: EllipticCurves.PointFormatType;
+ private readonly demHelper_: EciesAeadHkdfDemHelper;
+ private readonly headerSize_: number;
+ private readonly hkdfSalt_: Uint8Array|undefined;
+
+ /**
+ * @param hkdfHash the name of the HMAC algorithm, accepted names
+ * are: SHA-1, SHA-256 and SHA-512.
+ */
+ constructor(
+ recipientPrivateKey: JsonWebKey, kemRecipient: EciesHkdfKemRecipient,
+ hkdfHash: string, pointFormat: EllipticCurves.PointFormatType,
+ demHelper: EciesAeadHkdfDemHelper, opt_hkdfSalt?: Uint8Array) {
+ if (!recipientPrivateKey) {
+ throw new SecurityException('Recipient private key has to be non-null.');
+ }
+ if (!kemRecipient) {
+ throw new SecurityException('KEM recipient has to be non-null.');
+ }
+ if (!hkdfHash) {
+ throw new SecurityException('HKDF hash algorithm has to be non-null.');
+ }
+ if (!pointFormat) {
+ throw new SecurityException('Point format has to be non-null.');
+ }
+ if (!demHelper) {
+ throw new SecurityException('DEM helper has to be non-null.');
+ }
+ const {crv} = recipientPrivateKey;
+ if (!crv) {
+ throw new SecurityException('Curve has to be defined.');
+ }
+ const curveType = EllipticCurves.curveFromString(crv);
+ const headerSize =
+ EllipticCurves.encodingSizeInBytes(curveType, pointFormat);
+ this.kemRecipient_ = kemRecipient;
+ this.hkdfHash_ = hkdfHash;
+ this.pointFormat_ = pointFormat;
+ this.demHelper_ = demHelper;
+ this.headerSize_ = headerSize;
+ this.hkdfSalt_ = opt_hkdfSalt;
+ }
+
+ /**
+ * Decrypts ciphertext using opt_contextInfo as info parameter of the
+ * underlying HKDF.
+ *
+ * @override
+ */
+ async decrypt(ciphertext: Uint8Array, associatedData?: Uint8Array) {
+ if (ciphertext.length < this.headerSize_) {
+ throw new SecurityException('Ciphertext is too short.');
+ }
+
+ // Split the ciphertext to KEM token and AEAD ciphertext.
+ const kemToken = ciphertext.slice(0, this.headerSize_);
+ const ciphertextBody =
+ ciphertext.slice(this.headerSize_, ciphertext.length);
+ const aead = await this.getAead_(kemToken, associatedData);
+ return aead.decrypt(ciphertextBody);
+ }
+
+ private async getAead_(
+ kemToken: Uint8Array, opt_contextInfo?: Uint8Array|null): Promise<Aead> {
+ // Variable hkdfInfo is not optional for decapsulate method. Thus it should
+ // be an empty array in case that it is not defined by the caller of decrypt
+ // method.
+ if (!opt_contextInfo) {
+ opt_contextInfo = new Uint8Array(0);
+ }
+ const symmetricKey = await this.kemRecipient_.decapsulate(
+ kemToken, this.demHelper_.getDemKeySizeInBytes(), this.pointFormat_,
+ this.hkdfHash_, opt_contextInfo, this.hkdfSalt_);
+ return this.demHelper_.getAead(symmetricKey);
+ }
+}
+
+/**
+ * @param hkdfHash the name of the HMAC algorithm, accepted names
+ * are: SHA-1, SHA-256 and SHA-512.
+ */
+export async function fromJsonWebKey(
+ recipientPrivateKey: JsonWebKey, hkdfHash: string,
+ pointFormat: EllipticCurves.PointFormatType,
+ demHelper: EciesAeadHkdfDemHelper,
+ opt_hkdfSalt?: Uint8Array): Promise<HybridDecrypt> {
+ if (!recipientPrivateKey) {
+ throw new SecurityException('Recipient private key has to be non-null.');
+ }
+ if (!hkdfHash) {
+ throw new SecurityException('HKDF hash algorithm has to be non-null.');
+ }
+ if (!pointFormat) {
+ throw new SecurityException('Point format has to be non-null.');
+ }
+ if (!demHelper) {
+ throw new SecurityException('DEM helper has to be non-null.');
+ }
+ if (!recipientPrivateKey) {
+ throw new SecurityException('Recipient private key has to be non-null.');
+ }
+ const kemRecipient = await kemRecipientFromJsonWebKey(recipientPrivateKey);
+ return new EciesAeadHkdfHybridDecrypt(
+ recipientPrivateKey, kemRecipient, hkdfHash, pointFormat, demHelper,
+ opt_hkdfSalt);
+}
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt_test.js b/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt_test.js
index 8af957d..d9c8b53 100644
--- a/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt_test.js
+++ b/javascript/subtle/ecies_aead_hkdf_hybrid_decrypt_test.js
@@ -18,11 +18,11 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
const DemHelper = goog.require('tink.hybrid.RegistryEciesAeadHkdfDemHelper');
-const EciesAeadHkdfHybridDecrypt = goog.require('tink.subtle.EciesAeadHkdfHybridDecrypt');
-const EciesAeadHkdfHybridEncrypt = goog.require('tink.subtle.EciesAeadHkdfHybridEncrypt');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
+const {fromJsonWebKey: decrypterFromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_hybrid_decrypt');
+const {fromJsonWebKey: encrypterFromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_hybrid_encrypt');
describe('ecies aead hkdf hybrid decrypt test', function() {
beforeEach(function() {
@@ -45,7 +45,7 @@
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const demHelper = new DemHelper(AeadKeyTemplates.aes128CtrHmacSha256());
- await EciesAeadHkdfHybridDecrypt.newInstance(
+ await decrypterFromJsonWebKey(
privateKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
});
@@ -63,9 +63,9 @@
const privateKey = await EllipticCurves.exportCryptoKey(keyPair.privateKey);
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const hybridEncrypt = await EciesAeadHkdfHybridEncrypt.newInstance(
+ const hybridEncrypt = await encrypterFromJsonWebKey(
publicKey, hkdfHash, pointFormat, demHelper);
- const hybridDecrypt = await EciesAeadHkdfHybridDecrypt.newInstance(
+ const hybridDecrypt = await decrypterFromJsonWebKey(
privateKey, hkdfHash, pointFormat, demHelper);
const plaintext = Random.randBytes(10);
@@ -90,11 +90,11 @@
const keyTemplate = AeadKeyTemplates.aes256CtrHmacSha256();
const demHelperEncrypt = new DemHelper(keyTemplate);
- const hybridEncrypt = await EciesAeadHkdfHybridEncrypt.newInstance(
+ const hybridEncrypt = await encrypterFromJsonWebKey(
publicKey, hkdfHash, pointFormat, demHelperEncrypt);
const demHelperDecrypt = new DemHelper(keyTemplate);
- const hybridDecrypt = await EciesAeadHkdfHybridDecrypt.newInstance(
+ const hybridDecrypt = await decrypterFromJsonWebKey(
privateKey, hkdfHash, pointFormat, demHelperDecrypt);
const plaintext = Random.randBytes(15);
@@ -111,23 +111,25 @@
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const hmacAlgorithms = ['SHA-1', 'SHA-256', 'SHA-512'];
const demHelper = new DemHelper(AeadKeyTemplates.aes256CtrHmacSha256());
- const curves = Object.keys(EllipticCurves.CurveType);
+ const curves = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
// Test the encryption for different HMAC algorithms and different types of
// curves.
for (let hkdfHash of hmacAlgorithms) {
for (let curve of curves) {
- const curveName =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveName = EllipticCurves.curveToString(curve);
const keyPair = await EllipticCurves.generateKeyPair('ECDH', curveName);
const privateKey =
await EllipticCurves.exportCryptoKey(keyPair.privateKey);
const publicKey =
await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const hybridEncrypt = await EciesAeadHkdfHybridEncrypt.newInstance(
+ const hybridEncrypt = await encrypterFromJsonWebKey(
publicKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
- const hybridDecrypt = await EciesAeadHkdfHybridDecrypt.newInstance(
+ const hybridDecrypt = await decrypterFromJsonWebKey(
privateKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
for (let i = 0; i < repetitions; ++i) {
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.js b/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.js
deleted file mode 100644
index 23a5a4a..0000000
--- a/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EciesAeadHkdfHybridEncrypt');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const EciesAeadHkdfDemHelper = goog.require('tink.subtle.EciesAeadHkdfDemHelper');
-const EciesHkdfKemSender = goog.require('tink.subtle.EciesHkdfKemSender');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const {HybridEncrypt} = goog.require('google3.third_party.tink.javascript.hybrid.internal.hybrid_encrypt');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
-/**
- * Implementation of ECIES AEAD HKDF hybrid encryption.
- *
- * @protected
- * @final
- */
-class EciesAeadHkdfHybridEncrypt extends HybridEncrypt {
- /**
- * @param {!EciesHkdfKemSender} kemSender
- * @param {string} hkdfHash the name of the HMAC algorithm, accepted names
- * are: SHA-1, SHA-256 and SHA-512.
- * @param {!EllipticCurves.PointFormatType} pointFormat
- * @param {!EciesAeadHkdfDemHelper} demHelper
- * @param {!Uint8Array=} opt_hkdfSalt
- */
- constructor(kemSender, hkdfHash, pointFormat, demHelper, opt_hkdfSalt) {
- super();
-
- // TODO(thaidn): do we actually need these null checks?
- if (!kemSender) {
- throw new SecurityException('KEM sender has to be non-null.');
- }
- if (!hkdfHash) {
- throw new SecurityException('HMAC algorithm has to be non-null.');
- }
- if (!pointFormat) {
- throw new SecurityException('Point format has to be non-null.');
- }
- if (!demHelper) {
- throw new SecurityException('DEM helper has to be non-null.');
- }
-
- /** @private @const {!EciesHkdfKemSender} */
- this.kemSender_ = kemSender;
- /** @private @const {string} */
- this.hkdfHash_ = hkdfHash;
- /** @private @const {!EllipticCurves.PointFormatType} */
- this.pointFormat_ = pointFormat;
- /** @private @const {!EciesAeadHkdfDemHelper} */
- this.demHelper_ = demHelper;
- /** @private @const {!Uint8Array|undefined} */
- this.hkdfSalt_ = opt_hkdfSalt;
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} recipientPublicKey
- * @param {string} hkdfHash the name of the HMAC algorithm, accepted names
- * are: SHA-1, SHA-256 and SHA-512.
- * @param {!EllipticCurves.PointFormatType} pointFormat
- * @param {!EciesAeadHkdfDemHelper} demHelper
- * @param {!Uint8Array=} opt_hkdfSalt
- *
- * @return {!Promise.<!HybridEncrypt>}
- */
- static async newInstance(
- recipientPublicKey, hkdfHash, pointFormat, demHelper, opt_hkdfSalt) {
- if (!recipientPublicKey) {
- throw new SecurityException('Recipient public key has to be non-null.');
- }
- if (!hkdfHash) {
- throw new SecurityException('HMAC algorithm has to be non-null.');
- }
- if (!pointFormat) {
- throw new SecurityException('Point format has to be non-null.');
- }
- if (!demHelper) {
- throw new SecurityException('DEM helper has to be non-null.');
- }
-
- const kemSender = await EciesHkdfKemSender.newInstance(recipientPublicKey);
- return new EciesAeadHkdfHybridEncrypt(
- kemSender, hkdfHash, pointFormat, demHelper, opt_hkdfSalt);
- }
-
- /**
- * Encrypts plaintext using opt_contextInfo as info parameter of the
- * underlying HKDF.
- *
- * @override
- */
- async encrypt(plaintext, opt_contextInfo) {
- // Variable hkdfInfo is not optional for encapsulate method. Thus it
- // should be an empty array in case that it is not defined by caller of this
- // method.
- if (!opt_contextInfo) {
- opt_contextInfo = new Uint8Array(0);
- }
-
- const keySizeInBytes = this.demHelper_.getDemKeySizeInBytes();
- const kemKey = await this.kemSender_.encapsulate(
- keySizeInBytes, this.pointFormat_, this.hkdfHash_, opt_contextInfo,
- this.hkdfSalt_);
- const aead = await this.demHelper_.getAead(kemKey['key']);
-
- const ciphertextBody = await aead.encrypt(plaintext);
- const header = kemKey['token'];
-
- return Bytes.concat(header, ciphertextBody);
- }
-}
-
-exports = EciesAeadHkdfHybridEncrypt;
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.ts b/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.ts
new file mode 100644
index 0000000..ab90952
--- /dev/null
+++ b/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt.ts
@@ -0,0 +1,103 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+import {HybridEncrypt} from '../hybrid/internal/hybrid_encrypt';
+
+import * as Bytes from './bytes';
+import {EciesAeadHkdfDemHelper} from './ecies_aead_hkdf_dem_helper';
+import * as sender from './ecies_hkdf_kem_sender';
+import * as EllipticCurves from './elliptic_curves';
+
+/**
+ * Implementation of ECIES AEAD HKDF hybrid encryption.
+ *
+ * @final
+ */
+export class EciesAeadHkdfHybridEncrypt implements HybridEncrypt {
+ private readonly kemSender_: sender.EciesHkdfKemSender;
+ private readonly hkdfHash_: string;
+ private readonly pointFormat_: EllipticCurves.PointFormatType;
+ private readonly demHelper_: EciesAeadHkdfDemHelper;
+ private readonly hkdfSalt_: Uint8Array|undefined;
+
+ /**
+ * @param hkdfHash the name of the HMAC algorithm, accepted names
+ * are: SHA-1, SHA-256 and SHA-512.
+ */
+ constructor(
+ kemSender: sender.EciesHkdfKemSender, hkdfHash: string,
+ pointFormat: EllipticCurves.PointFormatType,
+ demHelper: EciesAeadHkdfDemHelper, opt_hkdfSalt?: Uint8Array) {
+ // TODO(thaidn): do we actually need these null checks?
+ if (!kemSender) {
+ throw new SecurityException('KEM sender has to be non-null.');
+ }
+ if (!hkdfHash) {
+ throw new SecurityException('HMAC algorithm has to be non-null.');
+ }
+ if (!pointFormat) {
+ throw new SecurityException('Point format has to be non-null.');
+ }
+ if (!demHelper) {
+ throw new SecurityException('DEM helper has to be non-null.');
+ }
+ this.kemSender_ = kemSender;
+ this.hkdfHash_ = hkdfHash;
+ this.pointFormat_ = pointFormat;
+ this.demHelper_ = demHelper;
+ this.hkdfSalt_ = opt_hkdfSalt;
+ }
+
+ /**
+ * Encrypts plaintext using opt_contextInfo as info parameter of the
+ * underlying HKDF.
+ *
+ * @override
+ */
+ async encrypt(
+ plaintext: Uint8Array,
+ associatedData: Uint8Array = new Uint8Array(0)): Promise<Uint8Array> {
+ const keySizeInBytes = this.demHelper_.getDemKeySizeInBytes();
+ const kemKey = await this.kemSender_.encapsulate(
+ keySizeInBytes, this.pointFormat_, this.hkdfHash_, associatedData,
+ this.hkdfSalt_);
+ const aead = await this.demHelper_.getAead(kemKey['key']);
+ const ciphertextBody = await aead.encrypt(plaintext);
+ const header = kemKey['token'];
+ return Bytes.concat(header, ciphertextBody);
+ }
+}
+
+/**
+ * @param hkdfHash the name of the HMAC algorithm, accepted names
+ * are: SHA-1, SHA-256 and SHA-512.
+ */
+export async function fromJsonWebKey(
+ recipientPublicKey: JsonWebKey, hkdfHash: string,
+ pointFormat: EllipticCurves.PointFormatType,
+ demHelper: EciesAeadHkdfDemHelper,
+ opt_hkdfSalt?: Uint8Array): Promise<HybridEncrypt> {
+ if (!recipientPublicKey) {
+ throw new SecurityException('Recipient public key has to be non-null.');
+ }
+ if (!hkdfHash) {
+ throw new SecurityException('HMAC algorithm has to be non-null.');
+ }
+ if (!pointFormat) {
+ throw new SecurityException('Point format has to be non-null.');
+ }
+ if (!demHelper) {
+ throw new SecurityException('DEM helper has to be non-null.');
+ }
+ const kemSender = await sender.fromJsonWebKey(recipientPublicKey);
+ return new EciesAeadHkdfHybridEncrypt(
+ kemSender, hkdfHash, pointFormat, demHelper, opt_hkdfSalt);
+}
diff --git a/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt_test.js b/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt_test.js
index 42a7538..4d2242f 100644
--- a/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt_test.js
+++ b/javascript/subtle/ecies_aead_hkdf_hybrid_encrypt_test.js
@@ -17,11 +17,11 @@
const AeadConfig = goog.require('tink.aead.AeadConfig');
const AeadKeyTemplates = goog.require('tink.aead.AeadKeyTemplates');
-const EciesAeadHkdfHybridEncrypt = goog.require('tink.subtle.EciesAeadHkdfHybridEncrypt');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
-const Registry = goog.require('tink.Registry');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const Registry = goog.require('google3.third_party.tink.javascript.internal.registry');
const RegistryEciesAeadHkdfDemHelper = goog.require('tink.hybrid.RegistryEciesAeadHkdfDemHelper');
+const {fromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_aead_hkdf_hybrid_encrypt');
describe('ecies aead hkdf hybrid encrypt test', function() {
beforeEach(function() {
@@ -44,8 +44,7 @@
const demHelper = new RegistryEciesAeadHkdfDemHelper(
AeadKeyTemplates.aes128CtrHmacSha256());
- await EciesAeadHkdfHybridEncrypt.newInstance(
- publicKey, hkdfHash, pointFormat, demHelper);
+ await fromJsonWebKey(publicKey, hkdfHash, pointFormat, demHelper);
});
it('encrypt, different arguments', async function() {
@@ -58,14 +57,15 @@
// Test the encryption for different HMAC algorithms and different types of
// curves.
for (let hkdfHash of hmacAlgorithms) {
- for (let curve of Object.keys(EllipticCurves.CurveType)) {
- const curveName =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ for (let curve
+ of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521]) {
+ const curveName = EllipticCurves.curveToString(curve);
const keyPair = await EllipticCurves.generateKeyPair('ECDH', curveName);
const publicKey =
await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const hybridEncrypt = await EciesAeadHkdfHybridEncrypt.newInstance(
+ const hybridEncrypt = await fromJsonWebKey(
publicKey, hkdfHash, pointFormat, demHelper, hkdfSalt);
const plaintext = Random.randBytes(15);
diff --git a/javascript/subtle/ecies_hkdf_kem_recipient.js b/javascript/subtle/ecies_hkdf_kem_recipient.js
deleted file mode 100644
index f9f3f97..0000000
--- a/javascript/subtle/ecies_hkdf_kem_recipient.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EciesHkdfKemRecipient');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Hkdf = goog.require('tink.subtle.Hkdf');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
-/**
- * HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES recipient.
- */
-class EciesHkdfKemRecipient {
- /**
- * @param {!webCrypto.CryptoKey} privateKey
- */
- constructor(privateKey) {
- if (!privateKey) {
- throw new SecurityException('Private key has to be non-null.');
- }
- // CryptoKey should have the properties type and algorithm.
- if (privateKey.type !== 'private' || !privateKey.algorithm) {
- throw new SecurityException('Expected crypto key of type: private.');
- }
- /** @const @private {!webCrypto.CryptoKey} */
- this.privateKey_ = privateKey;
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} jwk
- * @return {!Promise.<!EciesHkdfKemRecipient>}
- * @static
- */
- static async newInstance(jwk) {
- const privateKey = await EllipticCurves.importPrivateKey('ECDH', jwk);
- return new EciesHkdfKemRecipient(privateKey);
- }
-
- /**
- * @param {!Uint8Array} kemToken the public ephemeral point.
- * @param {number} keySizeInBytes The length of the generated pseudorandom
- * string in bytes. The maximal size is 255 * DigestSize, where DigestSize
- * is the size of the underlying HMAC.
- * @param {!EllipticCurves.PointFormatType} pointFormat The format of the
- * public ephemeral point.
- * @param {string} hkdfHash the name of the hash function. Accepted names are
- * SHA-1, SHA-256 and SHA-512.
- * @param {!Uint8Array} hkdfInfo Context and application specific
- * information (can be a zero-length array).
- * @param {!Uint8Array=} opt_hkdfSalt Salt value (a non-secret random
- * value). If not provided, it is set to a string of hash length zeros.
- * @return {!Promise.<!Uint8Array>} The KEM key and token.
- */
- async decapsulate(
- kemToken, keySizeInBytes, pointFormat, hkdfHash, hkdfInfo, opt_hkdfSalt) {
- const jwk = EllipticCurves.pointDecode(
- this.privateKey_.algorithm['namedCurve'], pointFormat, kemToken);
- const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
- const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
- this.privateKey_, publicKey);
- const hkdfIkm = Bytes.concat(kemToken, sharedSecret);
- const kemKey = await Hkdf.compute(
- keySizeInBytes, hkdfHash, hkdfIkm, hkdfInfo, opt_hkdfSalt);
- return kemKey;
- }
-}
-
-exports = EciesHkdfKemRecipient;
diff --git a/javascript/subtle/ecies_hkdf_kem_recipient.ts b/javascript/subtle/ecies_hkdf_kem_recipient.ts
new file mode 100644
index 0000000..c97908d
--- /dev/null
+++ b/javascript/subtle/ecies_hkdf_kem_recipient.ts
@@ -0,0 +1,73 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+
+import * as Bytes from './bytes';
+import * as EllipticCurves from './elliptic_curves';
+import * as Hkdf from './hkdf';
+
+/**
+ * HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES recipient.
+ */
+export class EciesHkdfKemRecipient {
+ private readonly privateKey_: CryptoKey;
+
+ constructor(privateKey: CryptoKey) {
+ if (!privateKey) {
+ throw new SecurityException('Private key has to be non-null.');
+ }
+
+ // CryptoKey should have the properties type and algorithm.
+ if (privateKey.type !== 'private' || !privateKey.algorithm) {
+ throw new SecurityException('Expected crypto key of type: private.');
+ }
+ this.privateKey_ = privateKey;
+ }
+
+ /**
+ * @param kemToken the public ephemeral point.
+ * @param keySizeInBytes The length of the generated pseudorandom
+ * string in bytes. The maximal size is 255 * DigestSize, where DigestSize
+ * is the size of the underlying HMAC.
+ * @param pointFormat The format of the
+ * public ephemeral point.
+ * @param hkdfHash the name of the hash function. Accepted names are
+ * SHA-1, SHA-256 and SHA-512.
+ * @param hkdfInfo Context and application specific
+ * information (can be a zero-length array).
+ * @param opt_hkdfSalt Salt value (a non-secret random
+ * value). If not provided, it is set to a string of hash length zeros.
+ * @return The KEM key and token.
+ */
+ async decapsulate(
+ kemToken: Uint8Array, keySizeInBytes: number,
+ pointFormat: EllipticCurves.PointFormatType, hkdfHash: string,
+ hkdfInfo: Uint8Array, opt_hkdfSalt?: Uint8Array): Promise<Uint8Array> {
+ const {namedCurve}: Partial<EcKeyAlgorithm> = this.privateKey_.algorithm;
+ if (!namedCurve) {
+ throw new SecurityException('Curve has to be defined.');
+ }
+ const jwk = EllipticCurves.pointDecode(namedCurve, pointFormat, kemToken);
+ const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
+ const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
+ this.privateKey_, publicKey);
+ const hkdfIkm = Bytes.concat(kemToken, sharedSecret);
+ const kemKey = await Hkdf.compute(
+ keySizeInBytes, hkdfHash, hkdfIkm, hkdfInfo, opt_hkdfSalt);
+ return kemKey;
+ }
+}
+
+export async function fromJsonWebKey(jwk: JsonWebKey):
+ Promise<EciesHkdfKemRecipient> {
+ const privateKey = await EllipticCurves.importPrivateKey('ECDH', jwk);
+ return new EciesHkdfKemRecipient(privateKey);
+}
diff --git a/javascript/subtle/ecies_hkdf_kem_recipient_test.js b/javascript/subtle/ecies_hkdf_kem_recipient_test.js
index dbec990..8c687f9 100644
--- a/javascript/subtle/ecies_hkdf_kem_recipient_test.js
+++ b/javascript/subtle/ecies_hkdf_kem_recipient_test.js
@@ -15,12 +15,11 @@
goog.module('tink.subtle.EciesHkdfKemRecipientTest');
goog.setTestOnly('tink.subtle.EciesHkdfKemRecipientTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EciesHkdfKemRecipient = goog.require('tink.subtle.EciesHkdfKemRecipient');
-const EciesHkdfKemSender = goog.require('tink.subtle.EciesHkdfKemSender');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
-
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {EciesHkdfKemRecipient, fromJsonWebKey: recipientFromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_hkdf_kem_recipient');
+const {fromJsonWebKey: senderFromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_hkdf_kem_sender');
describe('ecies hkdf kem recipient test', function() {
beforeEach(function() {
@@ -37,8 +36,8 @@
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
const privateKey = await EllipticCurves.exportCryptoKey(keyPair.privateKey);
- const sender = await EciesHkdfKemSender.newInstance(publicKey);
- const recipient = await EciesHkdfKemRecipient.newInstance(privateKey);
+ const sender = await senderFromJsonWebKey(publicKey);
+ const recipient = await recipientFromJsonWebKey(privateKey);
for (let i = 1; i < 20; i++) {
const keySizeInBytes = i;
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
@@ -61,8 +60,8 @@
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
const privateKey = await EllipticCurves.exportCryptoKey(keyPair.privateKey);
- const sender = await EciesHkdfKemSender.newInstance(publicKey);
- const recipient = await EciesHkdfKemRecipient.newInstance(privateKey);
+ const sender = await senderFromJsonWebKey(publicKey);
+ const recipient = await recipientFromJsonWebKey(privateKey);
const keySizeInBytes = 16;
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const hkdfHash = 'SHA-256';
@@ -95,7 +94,7 @@
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
try {
- await EciesHkdfKemRecipient.newInstance(publicKey);
+ await recipientFromJsonWebKey(publicKey);
fail('An exception should be thrown.');
} catch (e) {
}
@@ -118,7 +117,7 @@
Bytes.toBase64(new Uint8Array(xLength), /* opt_webSafe = */ true);
let output;
try {
- const recipient = await EciesHkdfKemRecipient.newInstance(privateJwk);
+ const recipient = await recipientFromJsonWebKey(privateJwk);
const hkdfInfo = Bytes.fromHex(testVector.hkdfInfo);
const salt = Bytes.fromHex(testVector.salt);
output = await recipient.decapsulate(
@@ -147,11 +146,13 @@
});
it('encap decap, different params', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
const hashTypes = ['SHA-1', 'SHA-256', 'SHA-512'];
for (let curve of curveTypes) {
- const curveString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveString = EllipticCurves.curveToString(curve);
for (let hashType of hashTypes) {
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveString);
@@ -162,13 +163,13 @@
const publicKey =
await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const sender = await EciesHkdfKemSender.newInstance(publicKey);
+ const sender = await senderFromJsonWebKey(publicKey);
const kemKeyToken = await sender.encapsulate(
keySizeInBytes, pointFormat, hashType, hkdfInfo, hkdfSalt);
const privateKey =
await EllipticCurves.exportCryptoKey(keyPair.privateKey);
- const recipient = await EciesHkdfKemRecipient.newInstance(privateKey);
+ const recipient = await recipientFromJsonWebKey(privateKey);
const key = await recipient.decapsulate(
kemKeyToken['token'], keySizeInBytes, pointFormat, hashType,
hkdfInfo, hkdfSalt);
@@ -180,17 +181,19 @@
});
it('encap decap, modified token', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
const hashTypes = ['SHA-1', 'SHA-256', 'SHA-512'];
- for (let crvId of curveTypes) {
- const curve = EllipticCurves.CurveType[crvId];
+ for (let curve of curveTypes) {
const curveString = EllipticCurves.curveToString(curve);
for (let hashType of hashTypes) {
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveString);
const privateKey =
await EllipticCurves.exportCryptoKey(keyPair.privateKey);
- const recipient = await EciesHkdfKemRecipient.newInstance(privateKey);
+ const recipient = await recipientFromJsonWebKey(privateKey);
const keySizeInBytes = 32;
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const hkdfInfo = Random.randBytes(8);
@@ -219,7 +222,7 @@
Bytes.fromHex(testVector.privateKeyPoint));
privateJwk['d'] = Bytes.toBase64(
Bytes.fromHex(testVector.privateKeyValue), /* opt_webSafe = */ true);
- const recipient = await EciesHkdfKemRecipient.newInstance(privateJwk);
+ const recipient = await recipientFromJsonWebKey(privateJwk);
const hkdfInfo = Bytes.fromHex(testVector.hkdfInfo);
const salt = Bytes.fromHex(testVector.salt);
const output = await recipient.decapsulate(
diff --git a/javascript/subtle/ecies_hkdf_kem_sender.js b/javascript/subtle/ecies_hkdf_kem_sender.js
deleted file mode 100644
index 4f4de45..0000000
--- a/javascript/subtle/ecies_hkdf_kem_sender.js
+++ /dev/null
@@ -1,82 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EciesHkdfKemSender');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Hkdf = goog.require('tink.subtle.Hkdf');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
-/**
- * HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES sender.
- */
-class EciesHkdfKemSender {
- /**
- * @param {!webCrypto.CryptoKey} recipientPublicKey
- */
- constructor(recipientPublicKey) {
- if (!recipientPublicKey) {
- throw new SecurityException('Recipient public key has to be non-null.');
- }
- // CryptoKey should have the properties type and algorithm.
- if (recipientPublicKey.type !== 'public' || !recipientPublicKey.algorithm) {
- throw new SecurityException('Expected Crypto key of type: public.');
- }
- /** @const @private {!webCrypto.CryptoKey} */
- this.publicKey_ = recipientPublicKey;
- }
-
- /**
- * @param {!webCrypto.JsonWebKey} jwk
- * @return {!Promise.<!EciesHkdfKemSender>}
- * @static
- */
- static async newInstance(jwk) {
- const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
- return new EciesHkdfKemSender(publicKey);
- }
-
- /**
- * @param {number} keySizeInBytes The length of the generated pseudorandom
- * string in bytes. The maximal size is 255 * DigestSize, where DigestSize
- * is the size of the underlying HMAC.
- * @param {!EllipticCurves.PointFormatType} pointFormat The format of the
- * public ephemeral point.
- * @param {string} hkdfHash the name of the hash function. Accepted names are
- * SHA-1, SHA-256 and SHA-512.
- * @param {!Uint8Array} hkdfInfo Context and application specific
- * information (can be a zero-length array).
- * @param {!Uint8Array=} opt_hkdfSalt Salt value (a non-secret random
- * value). If not provided, it is set to a string of hash length zeros.
- * @return {!Promise.<{key:!Uint8Array, token:!Uint8Array}>} The KEM key and
- * token.
- */
- async encapsulate(
- keySizeInBytes, pointFormat, hkdfHash, hkdfInfo, opt_hkdfSalt) {
- const ephemeralKeyPair = await EllipticCurves.generateKeyPair(
- 'ECDH', this.publicKey_.algorithm['namedCurve']);
- const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
- /** @type {?} */ (ephemeralKeyPair).privateKey, this.publicKey_);
- const jwk = await EllipticCurves.exportCryptoKey(
- /** @type {?} */ (ephemeralKeyPair).publicKey);
- const kemToken = EllipticCurves.pointEncode(jwk.crv, pointFormat, jwk);
- const hkdfIkm = Bytes.concat(kemToken, sharedSecret);
- const kemKey = await Hkdf.compute(
- keySizeInBytes, hkdfHash, hkdfIkm, hkdfInfo, opt_hkdfSalt);
- return {'key': kemKey, 'token': kemToken};
- }
-}
-
-exports = EciesHkdfKemSender;
diff --git a/javascript/subtle/ecies_hkdf_kem_sender.ts b/javascript/subtle/ecies_hkdf_kem_sender.ts
new file mode 100644
index 0000000..097b037
--- /dev/null
+++ b/javascript/subtle/ecies_hkdf_kem_sender.ts
@@ -0,0 +1,80 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {SecurityException} from '../exception/security_exception';
+
+import * as Bytes from './bytes';
+import * as EllipticCurves from './elliptic_curves';
+import * as Hkdf from './hkdf';
+
+/**
+ * HKDF-based ECIES-KEM (key encapsulation mechanism) for ECIES sender.
+ */
+export class EciesHkdfKemSender {
+ private readonly publicKey_: CryptoKey;
+
+ constructor(recipientPublicKey: CryptoKey) {
+ if (!recipientPublicKey) {
+ throw new SecurityException('Recipient public key has to be non-null.');
+ }
+
+ // CryptoKey should have the properties type and algorithm.
+ if (recipientPublicKey.type !== 'public' || !recipientPublicKey.algorithm) {
+ throw new SecurityException('Expected Crypto key of type: public.');
+ }
+ this.publicKey_ = recipientPublicKey;
+ }
+
+ /**
+ * @param keySizeInBytes The length of the generated pseudorandom
+ * string in bytes. The maximal size is 255 * DigestSize, where DigestSize
+ * is the size of the underlying HMAC.
+ * @param pointFormat The format of the
+ * public ephemeral point.
+ * @param hkdfHash the name of the hash function. Accepted names are
+ * SHA-1, SHA-256 and SHA-512.
+ * @param hkdfInfo Context and application specific
+ * information (can be a zero-length array).
+ * @param opt_hkdfSalt Salt value (a non-secret random
+ * value). If not provided, it is set to a string of hash length zeros.
+ * @return The KEM key and
+ * token.
+ */
+ async encapsulate(
+ keySizeInBytes: number, pointFormat: EllipticCurves.PointFormatType,
+ hkdfHash: string, hkdfInfo: Uint8Array, opt_hkdfSalt?: Uint8Array):
+ Promise<{key: Uint8Array, token: Uint8Array}> {
+ const {namedCurve}: Partial<EcKeyAlgorithm> = this.publicKey_.algorithm;
+ if (!namedCurve) {
+ throw new SecurityException('Curve has to be defined.');
+ }
+ const ephemeralKeyPair =
+ await EllipticCurves.generateKeyPair('ECDH', namedCurve);
+ const sharedSecret = await EllipticCurves.computeEcdhSharedSecret(
+ ephemeralKeyPair.privateKey, this.publicKey_);
+ const jwk =
+ await EllipticCurves.exportCryptoKey(ephemeralKeyPair.publicKey);
+ const {crv} = jwk;
+ if (!crv) {
+ throw new SecurityException('Curve has to be defined.');
+ }
+ const kemToken = EllipticCurves.pointEncode(crv, pointFormat, jwk);
+ const hkdfIkm = Bytes.concat(kemToken, sharedSecret);
+ const kemKey = await Hkdf.compute(
+ keySizeInBytes, hkdfHash, hkdfIkm, hkdfInfo, opt_hkdfSalt);
+ return {'key': kemKey, 'token': kemToken};
+ }
+}
+
+export async function fromJsonWebKey(jwk: JsonWebKey):
+ Promise<EciesHkdfKemSender> {
+ const publicKey = await EllipticCurves.importPublicKey('ECDH', jwk);
+ return new EciesHkdfKemSender(publicKey);
+}
diff --git a/javascript/subtle/ecies_hkdf_kem_sender_test.js b/javascript/subtle/ecies_hkdf_kem_sender_test.js
index 765afee..3442e2a 100644
--- a/javascript/subtle/ecies_hkdf_kem_sender_test.js
+++ b/javascript/subtle/ecies_hkdf_kem_sender_test.js
@@ -15,17 +15,16 @@
goog.module('tink.subtle.EciesHkdfKemSenderTest');
goog.setTestOnly('tink.subtle.EciesHkdfKemSenderTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EciesHkdfKemSender = goog.require('tink.subtle.EciesHkdfKemSender');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
-
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {EciesHkdfKemSender, fromJsonWebKey} = goog.require('google3.third_party.tink.javascript.subtle.ecies_hkdf_kem_sender');
describe('ecies hkdf kem sender test', function() {
it('encapsulate, always generate random key', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const sender = await EciesHkdfKemSender.newInstance(publicKey);
+ const sender = await fromJsonWebKey(publicKey);
const keySizeInBytes = 32;
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const hkdfHash = 'SHA-256';
@@ -46,7 +45,7 @@
it('encapsulate, non integer key size', async function() {
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const publicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
- const sender = await EciesHkdfKemSender.newInstance(publicKey);
+ const sender = await fromJsonWebKey(publicKey);
const pointFormat = EllipticCurves.PointFormatType.UNCOMPRESSED;
const hkdfHash = 'SHA-256';
const hkdfInfo = Random.randBytes(32);
@@ -68,19 +67,20 @@
});
it('new instance, invalid parameters', async function() {
- // Test newInstance with public key instead private key.
+ // Test fromJsonWebKey with public key instead private key.
const keyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const privateKey = await EllipticCurves.exportCryptoKey(keyPair.privateKey);
try {
- await EciesHkdfKemSender.newInstance(privateKey);
+ await fromJsonWebKey(privateKey);
fail('An exception should be thrown.');
} catch (e) {
}
});
it('new instance, invalid public key', async function() {
- for (let crv of Object.keys(EllipticCurves.CurveType)) {
- const curve = EllipticCurves.CurveType[crv];
+ for (let curve
+ of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521]) {
const crvString = EllipticCurves.curveToString(curve);
const keyPair = await EllipticCurves.generateKeyPair('ECDH', crvString);
const publicJwk = await EllipticCurves.exportCryptoKey(keyPair.publicKey);
@@ -93,7 +93,7 @@
const hkdfInfo = Random.randBytes(10);
const salt = Random.randBytes(8);
try {
- const sender = await EciesHkdfKemSender.newInstance(publicJwk);
+ const sender = await fromJsonWebKey(publicJwk);
await sender.encapsulate(
/* keySizeInBytes = */ 32,
EllipticCurves.PointFormatType.UNCOMPRESSED,
diff --git a/javascript/subtle/elliptic_curves.js b/javascript/subtle/elliptic_curves.js
deleted file mode 100644
index eee48e9..0000000
--- a/javascript/subtle/elliptic_curves.js
+++ /dev/null
@@ -1,532 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @fileoverview Common enums.
- */
-
-goog.module('tink.subtle.EllipticCurves');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-
-/**
- * Supported elliptic curves.
- * @enum {number}
- */
-const CurveType = {
- P256: 1,
- P384: 2,
- P521: 3,
-};
-
-/**
- * Supported point format.
- * @enum {number}
- */
-const PointFormatType = {
- UNCOMPRESSED: 1,
- COMPRESSED: 2,
- // Like UNCOMPRESSED but without the \x04 prefix. Crunchy uses this format.
- // DO NOT USE unless you are a Crunchy user moving to Tink.
- DO_NOT_USE_CRUNCHY_UNCOMPRESSED: 3,
-};
-
-/**
- * Supported ECDSA signature encoding.
- * @enum {number}
- */
-const EcdsaSignatureEncodingType = {
- // The DER signature is encoded using ASN.1
- // (https://tools.ietf.org/html/rfc5480#appendix-A):
- // ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }. In particular, the
- // encoding is:
- // 0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s.
- DER: 1,
- // The IEEE_P1363 signature's format is r || s, where r and s are zero-padded
- // and have the same size in bytes as the order of the curve. For example, for
- // NIST P-256 curve, r and s are zero-padded to 32 bytes.
- IEEE_P1363: 2,
-};
-
-/**
- * Transform an ECDSA signature in DER encoding to IEEE P1363 encoding.
- *
- * @param {!Uint8Array} der the ECDSA signature in DER encoding
- * @param {number} ieeeLength the length of the ECDSA signature in IEEE
- * encoding. This is usually 2 * size of the elliptic curve field.
- * @return {!Uint8Array} ECDSA signature in IEEE encoding
- */
-const ecdsaDer2Ieee = function(der, ieeeLength) {
- if (!isValidDerEcdsaSignature(der)) {
- throw new InvalidArgumentsException('invalid DER signature');
- }
- if (!Number.isInteger(ieeeLength) || ieeeLength < 0) {
- throw new InvalidArgumentsException(
- 'ieeeLength must be a nonnegative integer');
- }
- const ieee = new Uint8Array(ieeeLength);
- const length = der[1] & 0xff;
- let offset = 1 /* 0x30 */ + 1 /* totalLength */;
- if (length >= 128) {
- offset++; // Long form length
- }
- offset++; // 0x02
- const rLength = der[offset++];
- let extraZero = 0;
- if (der[offset] === 0) {
- extraZero = 1;
- }
- const rOffset = ieeeLength / 2 - rLength + extraZero;
- ieee.set(der.subarray(offset + extraZero, offset + rLength), rOffset);
- offset += rLength /* r byte array */ + 1 /* 0x02 */;
- const sLength = der[offset++];
- extraZero = 0;
- if (der[offset] === 0) {
- extraZero = 1;
- }
- const sOffset = ieeeLength - sLength + extraZero;
- ieee.set(der.subarray(offset + extraZero, offset + sLength), sOffset);
- return ieee;
-};
-
-/**
- * Transform an ECDSA signature in IEEE 1363 encoding to DER encoding.
- *
- * @param {!Uint8Array} ieee the ECDSA signature in IEEE encoding
- * @return {!Uint8Array} ECDSA signature in DER encoding
- */
-const ecdsaIeee2Der = function(ieee) {
- if (ieee.length % 2 != 0 || ieee.length == 0 || ieee.length > 132) {
- throw new InvalidArgumentsException(
- 'Invalid IEEE P1363 signature encoding. Length: ' + ieee.length);
- }
- const r = toUnsignedBigNum(ieee.subarray(0, ieee.length / 2));
- const s = toUnsignedBigNum(ieee.subarray(ieee.length / 2, ieee.length));
-
- let offset = 0;
- const length = 1 + 1 + r.length + 1 + 1 + s.length;
- let der;
- if (length >= 128) {
- der = new Uint8Array(length + 3);
- der[offset++] = 0x30;
- der[offset++] = 0x80 + 0x01;
- der[offset++] = length;
- } else {
- der = new Uint8Array(length + 2);
- der[offset++] = 0x30;
- der[offset++] = length;
- }
- der[offset++] = 0x02;
- der[offset++] = r.length;
- der.set(r, offset);
- offset += r.length;
- der[offset++] = 0x02;
- der[offset++] = s.length;
- der.set(s, offset);
- return der;
-};
-
-/**
- * Validate that the ECDSA signature is in DER encoding, based on
- * https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki.
- *
- * @param {!Uint8Array} sig an ECDSA siganture
- * @return {boolean}
- */
-const isValidDerEcdsaSignature = function(sig) {
- // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
- // * total-length: 1-byte or 2-byte length descriptor of everything that
- // follows.
- // * R-length: 1-byte length descriptor of the R value that follows.
- // * R: arbitrary-length big-endian encoded R value. It must use the shortest
- // possible encoding for a positive integers (which means no null bytes at
- // the start, except a single one when the next byte has its highest bit
- // set).
- // * S-length: 1-byte length descriptor of the S value that follows.
- // * S: arbitrary-length big-endian encoded S value. The same rules apply.
- if (sig.length < 1 /* 0x30 */
- + 1 /* total-length */
- + 1 /* 0x02 */
- + 1 /* R-length */
- + 1 /* R */
- + 1 /* 0x02 */
- + 1 /* S-length */
- + 1 /* S */) {
- // Signature is too short.
- return false;
- }
-
- // Checking bytes from left to right.
-
- // byte #1: a signature is of type 0x30 (compound).
- if (sig[0] != 0x30) {
- return false;
- }
-
- // byte #2 and maybe #3: the total length of the signature.
- let totalLen = sig[1] & 0xff;
- let totalLenLen =
- 1; // the length of the total length field, could be 2-byte.
- if (totalLen == 129) {
- // The signature is >= 128 bytes thus total length field is in long-form
- // encoding and occupies 2 bytes.
- totalLenLen = 2;
- // byte #3 is the total length.
- totalLen = sig[2] & 0xff;
- if (totalLen < 128) {
- // Length in long-form encoding must be >= 128.
- return false;
- }
- } else if (totalLen == 128 || totalLen > 129) {
- // Impossible values for the second byte.
- return false;
- }
-
- // Make sure the length covers the entire sig.
- if (totalLen != sig.length - 1 - totalLenLen) {
- return false;
- }
-
- // Start checking R.
- // Check whether the R element is an integer.
- if (sig[1 + totalLenLen] != 0x02) {
- return false;
- }
- // Extract the length of the R element.
- const rLen = sig[1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */] & 0xff;
- // Make sure the length of the S element is still inside the signature.
- if (1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */ + 1 /* rLen */ + rLen +
- 1 /* 0x02 */
- >= sig.length) {
- return false;
- }
- // Zero-length integers are not allowed for R.
- if (rLen == 0) {
- return false;
- }
- // Negative numbers are not allowed for R.
- if ((sig[3 + totalLenLen] & 0xff) >= 128) {
- return false;
- }
- // Null bytes at the start of R are not allowed, unless R would
- // otherwise be interpreted as a negative number.
- if (rLen > 1 && (sig[3 + totalLenLen] == 0x00) &&
- ((sig[4 + totalLenLen] & 0xff) < 128)) {
- return false;
- }
-
- // Start checking S.
- // Check whether the S element is an integer.
- if (sig[3 + totalLenLen + rLen] != 0x02) {
- return false;
- }
- // Extract the length of the S element.
- const sLen = sig[1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */ + 1 /* rLen */ +
- rLen + 1 /* 0x02 */] &
- 0xff;
- // Verify that the length of the signature matches the sum of the length of
- // the elements.
- if (1 /* 0x30 */
- + totalLenLen + 1 /* 0x02 */
- + 1 /* rLen */
- + rLen + 1 /* 0x02 */
- + 1 /* sLen */
- + sLen !=
- sig.length) {
- return false;
- }
- // Zero-length integers are not allowed for S.
- if (sLen == 0) {
- return false;
- }
- // Negative numbers are not allowed for S.
- if ((sig[5 + totalLenLen + rLen] & 0xff) >= 128) {
- return false;
- }
- // Null bytes at the start of S are not allowed, unless S would
- // otherwise be interpreted as a negative number.
- if (sLen > 1 && (sig[5 + totalLenLen + rLen] == 0x00) &&
- ((sig[6 + totalLenLen + rLen] & 0xff) < 128)) {
- return false;
- }
-
- return true;
-};
-
-/**
- * Transform a big integer in big endian to minimal unsigned form which has
- * no extra zero at the beginning except when the highest bit is set.
- *
- * @param {!Uint8Array} bytes
- * @return {!Uint8Array}
- */
-const toUnsignedBigNum = function(bytes) {
- // Remove zero prefixes.
- let start = 0;
- while (start < bytes.length && bytes[start] == 0) {
- start++;
- }
- if (start == bytes.length) {
- start = bytes.length - 1;
- }
-
- let extraZero = 0;
- // If the 1st bit is not zero, add 1 zero byte.
- if ((bytes[start] & 0x80) == 0x80) {
- // Add extra zero.
- extraZero = 1;
- }
- const res = new Uint8Array(bytes.length - start + extraZero);
- res.set(bytes.subarray(start), extraZero);
- return res;
-};
-
-/**
- * @param {!CurveType} curve
- * @return {string}
- */
-const curveToString = function(curve) {
- switch (curve) {
- case CurveType.P256:
- return 'P-256';
- case CurveType.P384:
- return 'P-384';
- case CurveType.P521:
- return 'P-521';
- }
- throw new InvalidArgumentsException('unknown curve: ' + curve);
-};
-
-/**
- * @param {string} curve
- * @return {!CurveType}
- */
-const curveFromString = function(curve) {
- switch (curve) {
- case 'P-256':
- return CurveType.P256;
- case 'P-384':
- return CurveType.P384;
- case 'P-521':
- return CurveType.P521;
- }
- throw new InvalidArgumentsException('unknown curve: ' + curve);
-};
-
-/**
- * @param {string} curve
- * @param {!PointFormatType} format
- * @param {!webCrypto.JsonWebKey} point
- * @return {!Uint8Array}
- */
-const pointEncode = function(curve, format, point) {
- const fieldSize = fieldSizeInBytes(curveFromString(curve));
- switch (format) {
- case PointFormatType.UNCOMPRESSED:
- let result = new Uint8Array(1 + 2 * fieldSize);
- result[0] = 0x04;
- result.set(Bytes.fromBase64(point.x, /* opt_webSafe = */ true), 1);
- result.set(
- Bytes.fromBase64(point.y, /* opt_webSafe = */ true), 1 + fieldSize);
- return result;
- }
- throw new InvalidArgumentsException('invalid format');
-};
-
-/**
- * @param {string} curve
- * @param {!PointFormatType} format
- * @param {!Uint8Array} point
- * @return {!webCrypto.JsonWebKey}
- */
-const pointDecode = function(curve, format, point) {
- const fieldSize = fieldSizeInBytes(curveFromString(curve));
- switch (format) {
- case PointFormatType.UNCOMPRESSED:
- if (point.length != 1 + 2 * fieldSize || point[0] != 0x04) {
- throw new InvalidArgumentsException('invalid point');
- }
- let result = /** @type {!webCrypto.JsonWebKey} */ ({
- 'kty': 'EC',
- 'crv': curve,
- 'x': Bytes.toBase64(
- new Uint8Array(point.subarray(1, 1 + fieldSize)),
- true /* websafe */),
- 'y': Bytes.toBase64(
- new Uint8Array(point.subarray(1 + fieldSize, point.length)),
- true /* websafe */),
- 'ext': true,
- });
- return result;
- }
- throw new InvalidArgumentsException('invalid format');
-};
-
-/**
- * @param {!CurveType} curve
- * @param {!Uint8Array} x
- * @param {!Uint8Array} y
- * @param {?Uint8Array=} d
- *
- * @return {!webCrypto.JsonWebKey}
- */
-const getJsonWebKey = function(curve, x, y, d) {
- const key = /** @type {!webCrypto.JsonWebKey} */ ({
- 'kty': 'EC',
- 'crv': curveToString(curve),
- 'x': Bytes.toBase64(x, true /* websafe */),
- 'y': Bytes.toBase64(y, true /* websafe */),
- 'ext': true,
- });
- if (d) {
- key['d'] = Bytes.toBase64(d, true /* websafe */);
- }
- return key;
-};
-
-/**
- * @param {!CurveType} curve
- * @return {number}
- */
-const fieldSizeInBytes = function(curve) {
- switch (curve) {
- case CurveType.P256:
- return 32;
- case CurveType.P384:
- return 48;
- case CurveType.P521:
- return 66;
- }
- throw new InvalidArgumentsException('unknown curve: ' + curve);
-};
-
-/**
- * @param {!CurveType} curve
- * @param {!PointFormatType} pointFormat
- *
- * @return {number}
- */
-const encodingSizeInBytes = function(curve, pointFormat) {
- switch (pointFormat) {
- case PointFormatType.UNCOMPRESSED:
- return 2 * fieldSizeInBytes(curve) + 1;
- case PointFormatType.COMPRESSED:
- return fieldSizeInBytes(curve) + 1;
- case PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED:
- return 2 * fieldSizeInBytes(curve);
- }
- throw new InvalidArgumentsException('invalid format');
-};
-
-/**
- * @param {!webCrypto.CryptoKey} privateKey
- * @param {!webCrypto.CryptoKey} publicKey
- * @return {!Promise<!Uint8Array>}
- */
-const computeEcdhSharedSecret = async function(privateKey, publicKey) {
- const ecdhParams =
- /** @type {!webCrypto.AlgorithmIdentifier} */ (privateKey.algorithm);
- ecdhParams['public'] = publicKey;
- const fieldSizeInBits =
- 8 * fieldSizeInBytes(curveFromString(ecdhParams['namedCurve']));
- const sharedSecret = await window.crypto.subtle.deriveBits(
- ecdhParams, privateKey, fieldSizeInBits);
- return new Uint8Array(sharedSecret);
-};
-
-/**
- * @param {string} algorithm
- * @param {string} curve
- * @return {!Promise<!webCrypto.CryptoKeyPair>}
- */
-const generateKeyPair = async function(algorithm, curve) {
- if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
- throw new InvalidArgumentsException(
- 'algorithm must be either ECDH or ECDSA');
- }
- const params = /** @type {!webCrypto.AlgorithmIdentifier} */ (
- {'name': algorithm, 'namedCurve': curve});
- const ephemeralKeyPair = await window.crypto.subtle.generateKey(
- params, true /* extractable */,
- algorithm == 'ECDH' ? ['deriveKey', 'deriveBits'] :
- ['sign', 'verify'] /* usage */);
- return /** @type {!webCrypto.CryptoKeyPair} */ (ephemeralKeyPair);
-};
-
-/**
- * @param {!webCrypto.CryptoKey} cryptoKey
- * @return {!Promise<!webCrypto.JsonWebKey>}
- */
-const exportCryptoKey = async function(cryptoKey) {
- const jwk = await window.crypto.subtle.exportKey('jwk', cryptoKey);
- return /** @type {!webCrypto.JsonWebKey} */ (jwk);
-};
-
-/**
- * @param {string} algorithm
- * @param {!webCrypto.JsonWebKey} jwk
- * @return {!Promise<!webCrypto.CryptoKey>}
- */
-const importPublicKey = async function(algorithm, jwk) {
- if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
- throw new InvalidArgumentsException(
- 'algorithm must be either ECDH or ECDSA');
- }
- const publicKey = await window.crypto.subtle.importKey(
- 'jwk' /* format */, jwk,
- {'name': algorithm, 'namedCurve': jwk.crv} /* algorithm */,
- true /* extractable */,
- algorithm == 'ECDH' ? [] : ['verify'] /* usage */);
- return publicKey;
-};
-
-/**
- * @param {string} algorithm
- * @param {!webCrypto.JsonWebKey} jwk
- * @return {!Promise<!webCrypto.CryptoKey>}
- */
-const importPrivateKey = async function(algorithm, jwk) {
- if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
- throw new InvalidArgumentsException(
- 'algorithm must be either ECDH or ECDSA');
- }
- const privateKey = await window.crypto.subtle.importKey(
- 'jwk' /* format */, jwk /* key material */,
- {'name': algorithm, 'namedCurve': jwk.crv} /* algorithm */,
- true /* extractable */,
- algorithm == 'ECDH' ? ['deriveKey', 'deriveBits'] : ['sign'] /* usage */);
- return privateKey;
-};
-
-exports = {
- CurveType,
- EcdsaSignatureEncodingType,
- PointFormatType,
- computeEcdhSharedSecret,
- curveToString,
- curveFromString,
- ecdsaDer2Ieee,
- ecdsaIeee2Der,
- getJsonWebKey,
- isValidDerEcdsaSignature,
- encodingSizeInBytes,
- exportCryptoKey,
- fieldSizeInBytes,
- generateKeyPair,
- importPrivateKey,
- importPublicKey,
- pointDecode,
- pointEncode,
-};
diff --git a/javascript/subtle/elliptic_curves.ts b/javascript/subtle/elliptic_curves.ts
new file mode 100644
index 0000000..3e76be9
--- /dev/null
+++ b/javascript/subtle/elliptic_curves.ts
@@ -0,0 +1,542 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @fileoverview Common enums.
+ */
+
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
+
+import * as Bytes from './bytes';
+
+/**
+ * Supported elliptic curves.
+ */
+export enum CurveType {
+ P256 = 1,
+ P384,
+ P521
+}
+
+/**
+ * Supported point format.
+ */
+export enum PointFormatType {
+ UNCOMPRESSED = 1,
+ COMPRESSED,
+
+ // Like UNCOMPRESSED but without the \x04 prefix. Crunchy uses this format.
+ // DO NOT USE unless you are a Crunchy user moving to Tink.
+ DO_NOT_USE_CRUNCHY_UNCOMPRESSED
+}
+
+/**
+ * Supported ECDSA signature encoding.
+ */
+export enum EcdsaSignatureEncodingType {
+
+ // The DER signature is encoded using ASN.1
+ // (https://tools.ietf.org/html/rfc5480#appendix-A):
+ // ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }. In particular, the
+ // encoding is:
+ // 0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s.
+ DER = 1,
+
+ // The IEEE_P1363 signature's format is r || s, where r and s are zero-padded
+ // and have the same size in bytes as the order of the curve. For example, for
+ // NIST P-256 curve, r and s are zero-padded to 32 bytes.
+ IEEE_P1363
+}
+
+/**
+ * Transform an ECDSA signature in DER encoding to IEEE P1363 encoding.
+ *
+ * @param der the ECDSA signature in DER encoding
+ * @param ieeeLength the length of the ECDSA signature in IEEE
+ * encoding. This is usually 2 * size of the elliptic curve field.
+ * @return ECDSA signature in IEEE encoding
+ */
+export function ecdsaDer2Ieee(der: Uint8Array, ieeeLength: number): Uint8Array {
+ if (!isValidDerEcdsaSignature(der)) {
+ throw new InvalidArgumentsException('invalid DER signature');
+ }
+ if (!Number.isInteger(ieeeLength) || ieeeLength < 0) {
+ throw new InvalidArgumentsException(
+ 'ieeeLength must be a nonnegative integer');
+ }
+ const ieee = new Uint8Array(ieeeLength);
+ const length = der[1] & 255;
+ let offset = 1 +
+ /* 0x30 */
+ 1;
+
+ /* totalLength */
+ if (length >= 128) {
+ offset++;
+ }
+
+ // Long form length
+ offset++;
+
+ // 0x02
+ const rLength = der[offset++];
+ let extraZero = 0;
+ if (der[offset] === 0) {
+ extraZero = 1;
+ }
+ const rOffset = ieeeLength / 2 - rLength + extraZero;
+ ieee.set(der.subarray(offset + extraZero, offset + rLength), rOffset);
+ offset += rLength +
+ /* r byte array */
+ 1;
+
+ /* 0x02 */
+ const sLength = der[offset++];
+ extraZero = 0;
+ if (der[offset] === 0) {
+ extraZero = 1;
+ }
+ const sOffset = ieeeLength - sLength + extraZero;
+ ieee.set(der.subarray(offset + extraZero, offset + sLength), sOffset);
+ return ieee;
+}
+
+/**
+ * Transform an ECDSA signature in IEEE 1363 encoding to DER encoding.
+ *
+ * @param ieee the ECDSA signature in IEEE encoding
+ * @return ECDSA signature in DER encoding
+ */
+export function ecdsaIeee2Der(ieee: Uint8Array): Uint8Array {
+ if (ieee.length % 2 != 0 || ieee.length == 0 || ieee.length > 132) {
+ throw new InvalidArgumentsException(
+ 'Invalid IEEE P1363 signature encoding. Length: ' + ieee.length);
+ }
+ const r = toUnsignedBigNum(ieee.subarray(0, ieee.length / 2));
+ const s = toUnsignedBigNum(ieee.subarray(ieee.length / 2, ieee.length));
+ let offset = 0;
+ const length = 1 + 1 + r.length + 1 + 1 + s.length;
+ let der;
+ if (length >= 128) {
+ der = new Uint8Array(length + 3);
+ der[offset++] = 48;
+ der[offset++] = 128 + 1;
+ der[offset++] = length;
+ } else {
+ der = new Uint8Array(length + 2);
+ der[offset++] = 48;
+ der[offset++] = length;
+ }
+ der[offset++] = 2;
+ der[offset++] = r.length;
+ der.set(r, offset);
+ offset += r.length;
+ der[offset++] = 2;
+ der[offset++] = s.length;
+ der.set(s, offset);
+ return der;
+}
+
+/**
+ * Validate that the ECDSA signature is in DER encoding, based on
+ * https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki.
+ *
+ * @param sig an ECDSA siganture
+ */
+export function isValidDerEcdsaSignature(sig: Uint8Array): boolean {
+ // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
+ // * total-length: 1-byte or 2-byte length descriptor of everything that
+ // follows.
+ // * R-length: 1-byte length descriptor of the R value that follows.
+ // * R: arbitrary-length big-endian encoded R value. It must use the shortest
+ // possible encoding for a positive integers (which means no null bytes at
+ // the start, except a single one when the next byte has its highest bit
+ // set).
+ // * S-length: 1-byte length descriptor of the S value that follows.
+ // * S: arbitrary-length big-endian encoded S value. The same rules apply.
+ /* S */
+ if (sig.length < 1 +
+ /* 0x30 */
+ 1 +
+ /* total-length */
+ 1 +
+ /* 0x02 */
+ 1 +
+ /* R-length */
+ 1 +
+ /* R */
+ 1 +
+ /* 0x02 */
+ 1 +
+ /* S-length */
+ 1) {
+ // Signature is too short.
+ return false;
+ }
+
+ // Checking bytes from left to right.
+
+ // byte #1: a signature is of type 0x30 (compound).
+ if (sig[0] != 48) {
+ return false;
+ }
+
+ // byte #2 and maybe #3: the total length of the signature.
+ let totalLen = sig[1] & 255;
+ let totalLenLen = 1;
+
+ // the length of the total length field, could be 2-byte.
+ if (totalLen == 129) {
+ // The signature is >= 128 bytes thus total length field is in long-form
+ // encoding and occupies 2 bytes.
+ totalLenLen = 2;
+
+ // byte #3 is the total length.
+ totalLen = sig[2] & 255;
+ if (totalLen < 128) {
+ // Length in long-form encoding must be >= 128.
+ return false;
+ }
+ } else if (totalLen == 128 || totalLen > 129) {
+ // Impossible values for the second byte.
+ return false;
+ }
+
+
+ // Make sure the length covers the entire sig.
+ if (totalLen != sig.length - 1 - totalLenLen) {
+ return false;
+ }
+
+ // Start checking R.
+ // Check whether the R element is an integer.
+ if (sig[1 + totalLenLen] != 2) {
+ return false;
+ }
+
+ // Extract the length of the R element.
+ const rLen = sig[1 +
+ /* 0x30 */
+ totalLenLen + 1] &
+ /* 0x02 */
+ 255;
+
+ // Make sure the length of the S element is still inside the signature.
+ if (1 +
+ /* 0x30 */
+ totalLenLen + 1 +
+ /* 0x02 */
+ 1 +
+ /* rLen */
+ rLen + 1 >=
+ /* 0x02 */
+ sig.length) {
+ return false;
+ }
+
+ // Zero-length integers are not allowed for R.
+ if (rLen == 0) {
+ return false;
+ }
+
+ // Negative numbers are not allowed for R.
+ if ((sig[3 + totalLenLen] & 255) >= 128) {
+ return false;
+ }
+
+ // Null bytes at the start of R are not allowed, unless R would
+ // otherwise be interpreted as a negative number.
+ if (rLen > 1 && sig[3 + totalLenLen] == 0 &&
+ (sig[4 + totalLenLen] & 255) < 128) {
+ return false;
+ }
+
+ // Start checking S.
+ // Check whether the S element is an integer.
+ if (sig[3 + totalLenLen + rLen] != 2) {
+ return false;
+ }
+
+ // Extract the length of the S element.
+ const sLen = sig[1 +
+ /* 0x30 */
+ totalLenLen + 1 +
+ /* 0x02 */
+ 1 +
+ /* rLen */
+ rLen + 1] &
+ /* 0x02 */
+ 255;
+
+ // Verify that the length of the signature matches the sum of the length of
+ // the elements.
+ if (1 +
+ /* 0x30 */
+ totalLenLen + 1 +
+ /* 0x02 */
+ 1 +
+ /* rLen */
+ rLen + 1 +
+ /* 0x02 */
+ 1 +
+ /* sLen */
+ sLen !=
+ sig.length) {
+ return false;
+ }
+
+ // Zero-length integers are not allowed for S.
+ if (sLen == 0) {
+ return false;
+ }
+
+ // Negative numbers are not allowed for S.
+ if ((sig[5 + totalLenLen + rLen] & 255) >= 128) {
+ return false;
+ }
+
+ // Null bytes at the start of S are not allowed, unless S would
+ // otherwise be interpreted as a negative number.
+ if (sLen > 1 && sig[5 + totalLenLen + rLen] == 0 &&
+ (sig[6 + totalLenLen + rLen] & 255) < 128) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Transform a big integer in big endian to minimal unsigned form which has
+ * no extra zero at the beginning except when the highest bit is set.
+ *
+ */
+function toUnsignedBigNum(bytes: Uint8Array): Uint8Array {
+ // Remove zero prefixes.
+ let start = 0;
+ while (start < bytes.length && bytes[start] == 0) {
+ start++;
+ }
+ if (start == bytes.length) {
+ start = bytes.length - 1;
+ }
+ let extraZero = 0;
+
+ // If the 1st bit is not zero, add 1 zero byte.
+ if ((bytes[start] & 128) == 128) {
+ // Add extra zero.
+ extraZero = 1;
+ }
+ const res = new Uint8Array(bytes.length - start + extraZero);
+ res.set(bytes.subarray(start), extraZero);
+ return res;
+}
+
+export function curveToString(curve: CurveType): string {
+ switch (curve) {
+ case CurveType.P256:
+ return 'P-256';
+ case CurveType.P384:
+ return 'P-384';
+ case CurveType.P521:
+ return 'P-521';
+ }
+ throw new InvalidArgumentsException('unknown curve: ' + curve);
+}
+
+export function curveFromString(curve: string): CurveType {
+ switch (curve) {
+ case 'P-256':
+ return CurveType.P256;
+ case 'P-384':
+ return CurveType.P384;
+ case 'P-521':
+ return CurveType.P521;
+ }
+ throw new InvalidArgumentsException('unknown curve: ' + curve);
+}
+
+export function pointEncode(
+ curve: string, format: PointFormatType, point: JsonWebKey): Uint8Array {
+ const fieldSize = fieldSizeInBytes(curveFromString(curve));
+ switch (format) {
+ case PointFormatType.UNCOMPRESSED:
+ const {x, y} = point;
+ if (x === undefined) {
+ throw new InvalidArgumentsException('x must be provided');
+ }
+ if (y === undefined) {
+ throw new InvalidArgumentsException('y must be provided');
+ }
+ const result = new Uint8Array(1 + 2 * fieldSize);
+ result[0] = 4;
+ result.set(
+ /* opt_webSafe = */
+ Bytes.fromBase64(x, true), 1);
+ result.set(
+ /* opt_webSafe = */
+ Bytes.fromBase64(y, true), 1 + fieldSize);
+ return result;
+ }
+ throw new InvalidArgumentsException('invalid format');
+}
+
+export function pointDecode(
+ curve: string, format: PointFormatType, point: Uint8Array): JsonWebKey {
+ const fieldSize = fieldSizeInBytes(curveFromString(curve));
+ switch (format) {
+ case PointFormatType.UNCOMPRESSED:
+ if (point.length != 1 + 2 * fieldSize || point[0] != 4) {
+ throw new InvalidArgumentsException('invalid point');
+ }
+ const result = ({
+ 'kty': 'EC',
+ 'crv': curve,
+ 'x': Bytes.toBase64(
+ new Uint8Array(point.subarray(1, 1 + fieldSize)),
+ /* websafe */
+ true),
+ 'y': Bytes.toBase64(
+ new Uint8Array(point.subarray(1 + fieldSize, point.length)),
+ /* websafe */
+ true),
+ 'ext': true
+ } as JsonWebKey);
+ return result;
+ }
+ throw new InvalidArgumentsException('invalid format');
+}
+
+export function getJsonWebKey(
+ curve: CurveType, x: Uint8Array, y: Uint8Array,
+ d?: Uint8Array|null): JsonWebKey {
+ const key = ({
+ 'kty': 'EC',
+ 'crv': curveToString(curve),
+ 'x': Bytes.toBase64(
+ x,
+ /* websafe */
+ true),
+ 'y': Bytes.toBase64(
+ y,
+ /* websafe */
+ true),
+ 'ext': true
+ } as JsonWebKey);
+ if (d) {
+ key['d'] = Bytes.toBase64(
+ d,
+ /* websafe */
+ true);
+ }
+ return key;
+}
+
+export function fieldSizeInBytes(curve: CurveType): number {
+ switch (curve) {
+ case CurveType.P256:
+ return 32;
+ case CurveType.P384:
+ return 48;
+ case CurveType.P521:
+ return 66;
+ }
+ throw new InvalidArgumentsException('unknown curve: ' + curve);
+}
+
+export function encodingSizeInBytes(
+ curve: CurveType, pointFormat: PointFormatType): number {
+ switch (pointFormat) {
+ case PointFormatType.UNCOMPRESSED:
+ return 2 * fieldSizeInBytes(curve) + 1;
+ case PointFormatType.COMPRESSED:
+ return fieldSizeInBytes(curve) + 1;
+ case PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED:
+ return 2 * fieldSizeInBytes(curve);
+ }
+ throw new InvalidArgumentsException('invalid format');
+}
+
+export async function computeEcdhSharedSecret(
+ privateKey: CryptoKey, publicKey: CryptoKey): Promise<Uint8Array> {
+ const {namedCurve}: Partial<EcKeyImportParams> = privateKey.algorithm;
+ if (!namedCurve) {
+ throw new InvalidArgumentsException('namedCurve must be provided');
+ }
+ const ecdhParams = {'public': publicKey, ...privateKey.algorithm};
+ const fieldSizeInBits = 8 * fieldSizeInBytes(curveFromString(namedCurve));
+ const sharedSecret = await window.crypto.subtle.deriveBits(
+ ecdhParams, privateKey, fieldSizeInBits);
+ return new Uint8Array(sharedSecret);
+}
+
+export async function generateKeyPair(
+ algorithm: 'ECDH'|'ECDSA', curve: string): Promise<CryptoKeyPair> {
+ if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
+ throw new InvalidArgumentsException(
+ 'algorithm must be either ECDH or ECDSA');
+ }
+ const params = {'name': algorithm, 'namedCurve': curve};
+ const ephemeralKeyPair = await window.crypto.subtle.generateKey(
+ params, /* extractable= */ true,
+ algorithm == 'ECDH' ? ['deriveKey', 'deriveBits'] : ['sign', 'verify']);
+ return ephemeralKeyPair as CryptoKeyPair;
+}
+
+export async function exportCryptoKey(cryptoKey: CryptoKey):
+ Promise<JsonWebKey> {
+ const jwk = await window.crypto.subtle.exportKey('jwk', cryptoKey);
+ return (jwk as JsonWebKey);
+}
+
+export async function importPublicKey(
+ algorithm: string, jwk: JsonWebKey): Promise<CryptoKey> {
+ if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
+ throw new InvalidArgumentsException(
+ 'algorithm must be either ECDH or ECDSA');
+ }
+ const {crv} = jwk;
+ if (!crv) {
+ throw new InvalidArgumentsException('crv must be provided');
+ }
+ const publicKey = await window.crypto.subtle.importKey(
+ /* format */
+ 'jwk', jwk, {'name': algorithm, 'namedCurve': crv},
+ /* algorithm */
+ true,
+ /* extractable */
+ algorithm == 'ECDH' ? [] : ['verify']);
+
+ /* usage */
+ return publicKey;
+}
+
+export async function importPrivateKey(
+ algorithm: string, jwk: JsonWebKey): Promise<CryptoKey> {
+ if (algorithm != 'ECDH' && algorithm != 'ECDSA') {
+ throw new InvalidArgumentsException(
+ 'algorithm must be either ECDH or ECDSA');
+ }
+ const {crv} = jwk;
+ if (!crv) {
+ throw new InvalidArgumentsException('crv must be provided');
+ }
+ const privateKey = await window.crypto.subtle.importKey(
+ /* format */
+ 'jwk', jwk,
+ /* key material */
+ {'name': algorithm, 'namedCurve': crv},
+ /* algorithm */
+ true,
+ /* extractable */
+ algorithm == 'ECDH' ? ['deriveKey', 'deriveBits'] : ['sign']);
+
+ /* usage */
+ return privateKey;
+}
diff --git a/javascript/subtle/elliptic_curves_test.js b/javascript/subtle/elliptic_curves_test.js
index 30e5f98..674fa87 100644
--- a/javascript/subtle/elliptic_curves_test.js
+++ b/javascript/subtle/elliptic_curves_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.EllipticCurvesTest');
goog.setTestOnly('tink.subtle.EllipticCurvesTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EllipticCurves = goog.require('tink.subtle.EllipticCurves');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const EllipticCurves = goog.require('google3.third_party.tink.javascript.subtle.elliptic_curves');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const wycheproofEcdhTestVectors = goog.require('tink.subtle.wycheproofEcdhTestVectors');
describe('elliptic curves test', function() {
@@ -55,10 +55,12 @@
// Test that both ECDH public and private key are defined in the result.
it('generate key pair e c d h', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
for (let curve of curveTypes) {
- const curveTypeString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveTypeString);
expect(keyPair.privateKey != null).toBe(true);
@@ -68,10 +70,12 @@
// Test that both ECDSA public and private key are defined in the result.
it('generate key pair e c d s a', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
for (let curve of curveTypes) {
- const curveTypeString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDSA', curveTypeString);
expect(keyPair.privateKey != null).toBe(true);
@@ -82,10 +86,12 @@
// Test that when ECDH crypto key is exported and imported it gives the same
// key as the original one.
it('import export crypto key e c d h', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
for (let curve of curveTypes) {
- const curveTypeString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveTypeString);
@@ -106,10 +112,12 @@
// Test that when ECDSA crypto key is exported and imported it gives the same
// key as the original one.
it('import export crypto key e c d s a', async function() {
- const curveTypes = Object.keys(EllipticCurves.CurveType);
+ const curveTypes = [
+ EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521
+ ];
for (let curve of curveTypes) {
- const curveTypeString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDSA', curveTypeString);
@@ -131,7 +139,7 @@
// key as the original one.
it('import export json key e c d h', async function() {
for (let testKey of TEST_KEYS) {
- const jwk = /** @type{!webCrypto.JsonWebKey} */ ({
+ const jwk = /** @type {!JsonWebKey} */ ({
'kty': 'EC',
'crv': testKey.curve,
'x': Bytes.toBase64(Bytes.fromHex(testKey.x), true),
@@ -158,7 +166,7 @@
// same key as the original one.
it('import export json key e c d s a', async function() {
for (let testKey of TEST_KEYS) {
- const jwk = /** @type{!webCrypto.JsonWebKey} */ ({
+ const jwk = /** @type {!JsonWebKey} */ ({
'kty': 'EC',
'crv': testKey.curve,
'x': Bytes.toBase64(Bytes.fromHex(testKey.x), true),
@@ -261,9 +269,10 @@
const point = new Uint8Array(10);
const format = EllipticCurves.PointFormatType.UNCOMPRESSED;
- for (let curve of Object.keys(EllipticCurves.CurveType)) {
- const curveTypeString =
- EllipticCurves.curveToString(EllipticCurves.CurveType[curve]);
+ for (let curve
+ of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521]) {
+ const curveTypeString = EllipticCurves.curveToString(curve);
// It should throw an exception as the point array is too short.
try {
@@ -290,13 +299,14 @@
it('point encode decode', function() {
const format = EllipticCurves.PointFormatType.UNCOMPRESSED;
- for (let curve of Object.keys(EllipticCurves.CurveType)) {
- const curveType = EllipticCurves.CurveType[curve];
+ for (let curveType
+ of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
+ EllipticCurves.CurveType.P521]) {
const curveTypeString = EllipticCurves.curveToString(curveType);
const x = Random.randBytes(EllipticCurves.fieldSizeInBytes(curveType));
const y = Random.randBytes(EllipticCurves.fieldSizeInBytes(curveType));
- const point = /** @type {!webCrypto.JsonWebKey} */ ({
+ const point = /** @type {!JsonWebKey} */ ({
'kty': 'EC',
'crv': curveTypeString,
'x': Bytes.toBase64(x, /* websafe = */ true),
diff --git a/javascript/subtle/encrypt_then_authenticate.js b/javascript/subtle/encrypt_then_authenticate.js
deleted file mode 100644
index ac7f4c2..0000000
--- a/javascript/subtle/encrypt_then_authenticate.js
+++ /dev/null
@@ -1,136 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.EncryptThenAuthenticate');
-
-const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
-const AesCtr = goog.require('tink.subtle.AesCtr');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Hmac = goog.require('tink.subtle.Hmac');
-const IndCpaCipher = goog.require('tink.subtle.IndCpaCipher');
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * This primitive performs an encrypt-then-Mac operation on plaintext and
- * additional authenticated data (aad).
- *
- * The Mac is computed over `aad || ciphertext || size of aad`, thus it
- * doesn't violate https://en.wikipedia.org/wiki/Horton_Principle.
- *
- * This implementation is based on
- * http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05.
- *
- * @public
- * @final
- */
-class EncryptThenAuthenticate extends Aead {
- /**
- * @param {!IndCpaCipher} cipher
- * @param {number} ivSize the IV size in bytes
- * @param {!Mac} mac
- * @param {number} tagSize the MAC tag size in bytes
- * @throws {InvalidArgumentsException}
- */
- constructor(cipher, ivSize, mac, tagSize) {
- super();
-
- /** @const @private {!IndCpaCipher} */
- this.cipher_ = cipher;
-
- /** @const @private {number} */
- this.ivSize_ = ivSize;
-
- /** @const @private {!Mac} */
- this.mac_ = mac;
-
- /** @const @private {number} */
- this.tagSize_ = tagSize;
- }
-
- /**
- * @param {!Uint8Array} aesKey
- * @param {number} ivSize the size of the IV
- * @param {string} hmacHashAlgo accepted names are SHA-1, SHA-256 and SHA-512
- * @param {!Uint8Array} hmacKey
- * @param {number} tagSize the size of the tag
- * @return {!Promise.<!EncryptThenAuthenticate>}
- * @throws {InvalidArgumentsException}
- * @static
- */
- static async newAesCtrHmac(aesKey, ivSize, hmacHashAlgo, hmacKey, tagSize) {
- Validators.requireUint8Array(aesKey);
- Validators.requireUint8Array(hmacKey);
-
- const cipher = await AesCtr.newInstance(aesKey, ivSize);
- const mac = await Hmac.newInstance(hmacHashAlgo, hmacKey, tagSize);
- return new EncryptThenAuthenticate(cipher, ivSize, mac, tagSize);
- }
-
- /**
- * The plaintext is encrypted with an {@link IndCpaCipher}, then MAC
- * is computed over `aad || ciphertext || t` where t is aad's length in bits
- * represented as 64-bit bigendian unsigned integer. The final ciphertext
- * format is `ind-cpa ciphertext || mac`.
- *
- * @override
- */
- async encrypt(plaintext, opt_associatedData) {
- Validators.requireUint8Array(plaintext);
- const payload = await this.cipher_.encrypt(plaintext);
- let aad = new Uint8Array(0);
- if (opt_associatedData != null) {
- aad = opt_associatedData;
- Validators.requireUint8Array(opt_associatedData);
- }
- const aadLength = Bytes.fromNumber(aad.length * 8);
- const mac =
- await this.mac_.computeMac(Bytes.concat(aad, payload, aadLength));
- if (this.tagSize_ != mac.length) {
- throw new SecurityException(
- 'invalid tag size, expected ' + this.tagSize_ + ' but got ' +
- mac.length);
- }
- return Bytes.concat(payload, mac);
- }
-
- /**
- * @override
- */
- async decrypt(ciphertext, opt_associatedData) {
- Validators.requireUint8Array(ciphertext);
- if (ciphertext.length < this.ivSize_ + this.tagSize_) {
- throw new SecurityException('ciphertext too short');
- }
- const payload = new Uint8Array(
- ciphertext.subarray(0, ciphertext.length - this.tagSize_));
- let aad = new Uint8Array(0);
- if (opt_associatedData != null) {
- aad = opt_associatedData;
- Validators.requireUint8Array(opt_associatedData);
- }
- const aadLength = Bytes.fromNumber(aad.length * 8);
- const input = Bytes.concat(aad, payload, aadLength);
- const tag = new Uint8Array(ciphertext.subarray(payload.length));
- const isValidMac = await this.mac_.verifyMac(tag, input);
- if (!isValidMac) {
- throw new SecurityException('invalid MAC');
- }
- return await this.cipher_.decrypt(payload);
- }
-}
-
-exports = EncryptThenAuthenticate;
diff --git a/javascript/subtle/encrypt_then_authenticate.ts b/javascript/subtle/encrypt_then_authenticate.ts
new file mode 100644
index 0000000..f2392f2
--- /dev/null
+++ b/javascript/subtle/encrypt_then_authenticate.ts
@@ -0,0 +1,105 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {Aead} from '../aead/internal/aead';
+import {SecurityException} from '../exception/security_exception';
+import {Mac} from '../mac/internal/mac';
+
+import * as aesCtr from './aes_ctr';
+import * as Bytes from './bytes';
+import * as hmac from './hmac';
+import {IndCpaCipher} from './ind_cpa_cipher';
+import * as Validators from './validators';
+
+/**
+ * This primitive performs an encrypt-then-Mac operation on plaintext and
+ * additional authenticated data (aad).
+ *
+ * The Mac is computed over `aad || ciphertext || size of aad`, thus it
+ * doesn't violate https://en.wikipedia.org/wiki/Horton_Principle.
+ *
+ * This implementation is based on
+ * http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05.
+ *
+ * @final
+ */
+export class EncryptThenAuthenticate implements Aead {
+ /**
+ * @param ivSize the IV size in bytes
+ * @param tagSize the MAC tag size in bytes
+ * @throws {InvalidArgumentsException}
+ */
+ constructor(
+ private readonly cipher: IndCpaCipher, private readonly ivSize: number,
+ private readonly mac: Mac, private readonly tagSize: number) {}
+
+ /**
+ * The plaintext is encrypted with an {@link IndCpaCipher}, then MAC
+ * is computed over `aad || ciphertext || t` where t is aad's length in bits
+ * represented as 64-bit bigendian unsigned integer. The final ciphertext
+ * format is `ind-cpa ciphertext || mac`.
+ *
+ * @override
+ */
+ async encrypt(plaintext: Uint8Array, associatedData = new Uint8Array(0)):
+ Promise<Uint8Array> {
+ Validators.requireUint8Array(plaintext);
+ const payload = await this.cipher.encrypt(plaintext);
+ Validators.requireUint8Array(associatedData);
+ const aadLength = Bytes.fromNumber(associatedData.length * 8);
+ const mac = await this.mac.computeMac(
+ Bytes.concat(associatedData, payload, aadLength));
+ if (this.tagSize != mac.length) {
+ throw new SecurityException(
+ 'invalid tag size, expected ' + this.tagSize + ' but got ' +
+ mac.length);
+ }
+ return Bytes.concat(payload, mac);
+ }
+
+ /**
+ * @override
+ */
+ async decrypt(ciphertext: Uint8Array, associatedData = new Uint8Array(0)):
+ Promise<Uint8Array> {
+ Validators.requireUint8Array(ciphertext);
+ if (ciphertext.length < this.ivSize + this.tagSize) {
+ throw new SecurityException('ciphertext too short');
+ }
+ const payload = new Uint8Array(
+ ciphertext.subarray(0, ciphertext.length - this.tagSize));
+ Validators.requireUint8Array(associatedData);
+ const aadLength = Bytes.fromNumber(associatedData.length * 8);
+ const input = Bytes.concat(associatedData, payload, aadLength);
+ const tag = new Uint8Array(ciphertext.subarray(payload.length));
+ const isValidMac = await this.mac.verifyMac(tag, input);
+ if (!isValidMac) {
+ throw new SecurityException('invalid MAC');
+ }
+ return this.cipher.decrypt(payload);
+ }
+}
+
+/**
+ * @param ivSize the size of the IV
+ * @param hmacHashAlgo accepted names are SHA-1, SHA-256 and SHA-512
+ * @param tagSize the size of the tag
+ * @throws {InvalidArgumentsException}
+ * @static
+ */
+export async function aesCtrHmacFromRawKeys(
+ aesKey: Uint8Array, ivSize: number, hmacHashAlgo: string,
+ hmacKey: Uint8Array, tagSize: number): Promise<EncryptThenAuthenticate> {
+ Validators.requireUint8Array(aesKey);
+ Validators.requireUint8Array(hmacKey);
+ const cipher = await aesCtr.fromRawKey(aesKey, ivSize);
+ const mac = await hmac.fromRawKey(hmacHashAlgo, hmacKey, tagSize);
+ return new EncryptThenAuthenticate(cipher, ivSize, mac, tagSize);
+}
diff --git a/javascript/subtle/encrypt_then_authenticate_test.js b/javascript/subtle/encrypt_then_authenticate_test.js
index c8e8d79..0519f1f 100644
--- a/javascript/subtle/encrypt_then_authenticate_test.js
+++ b/javascript/subtle/encrypt_then_authenticate_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.EncryptThenAuthenticateTest');
goog.setTestOnly('tink.subtle.EncryptThenAuthenticateTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const EncryptThenAuthenticate = goog.require('tink.subtle.EncryptThenAuthenticate');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {aesCtrHmacFromRawKeys} = goog.require('google3.third_party.tink.javascript.subtle.encrypt_then_authenticate');
describe('encrypt then authenticate test', function() {
beforeEach(function() {
@@ -31,7 +31,7 @@
});
it('basic', async function() {
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Random.randBytes(16) /* aesKey */, 12 /* ivSize */, 'SHA-256',
Random.randBytes(16) /* hmacKey */, 10 /* tagSize */);
for (let i = 0; i < 100; i++) {
@@ -40,12 +40,11 @@
let plaintext = await aead.decrypt(ciphertext);
expect(Bytes.toHex(plaintext)).toBe(Bytes.toHex(msg));
- let aad = null;
- ciphertext = await aead.encrypt(msg, aad);
- plaintext = await aead.decrypt(ciphertext, aad);
+ ciphertext = await aead.encrypt(msg);
+ plaintext = await aead.decrypt(ciphertext);
expect(Bytes.toHex(plaintext)).toBe(Bytes.toHex(msg));
- aad = Random.randBytes(20);
+ const aad = Random.randBytes(20);
ciphertext = await aead.encrypt(msg, aad);
plaintext = await aead.decrypt(ciphertext, aad);
expect(Bytes.toHex(plaintext)).toBe(Bytes.toHex(msg));
@@ -53,7 +52,7 @@
});
it('probabilistic encryption', async function() {
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Random.randBytes(16) /* aesKey */, 12 /* ivSize */, 'SHA-256',
Random.randBytes(16) /* hmacKey */, 10 /* tagSize */);
const msg = Random.randBytes(20);
@@ -67,7 +66,7 @@
});
it('bit flip ciphertext', async function() {
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Random.randBytes(16) /* aesKey */, 16 /* ivSize */, 'SHA-256',
Random.randBytes(16) /* hmacKey */, 16 /* tagSize */);
const plaintext = Random.randBytes(8);
@@ -88,7 +87,7 @@
});
it('bit flip aad', async function() {
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Random.randBytes(16) /* aesKey */, 16 /* ivSize */, 'SHA-256',
Random.randBytes(16) /* hmacKey */, 16 /* tagSize */);
const plaintext = Random.randBytes(8);
@@ -109,7 +108,7 @@
});
it('truncation', async function() {
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Random.randBytes(16) /* aesKey */, 16 /* ivSize */, 'SHA-256',
Random.randBytes(16) /* hmacKey */, 16 /* tagSize */);
const plaintext = Random.randBytes(8);
@@ -184,7 +183,7 @@
];
for (let i = 0; i < RFC_TEST_VECTORS.length; i++) {
const testVector = RFC_TEST_VECTORS[i];
- const aead = await EncryptThenAuthenticate.newAesCtrHmac(
+ const aead = await aesCtrHmacFromRawKeys(
Bytes.fromHex(testVector['encryptionKey']), testVector['ivSize'],
testVector['hashAlgoName'], Bytes.fromHex(testVector['macKey']),
testVector['tagSize']);
diff --git a/javascript/subtle/hkdf.js b/javascript/subtle/hkdf.ts
similarity index 70%
rename from javascript/subtle/hkdf.js
rename to javascript/subtle/hkdf.ts
index a50831c..5313dd7 100644
--- a/javascript/subtle/hkdf.js
+++ b/javascript/subtle/hkdf.ts
@@ -1,43 +1,40 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
/**
* @fileoverview An implementation of HKDF, RFC 5869.
*/
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
-goog.module('tink.subtle.Hkdf');
-
-const Hmac = goog.require('tink.subtle.Hmac');
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const Validators = goog.require('tink.subtle.Validators');
+import {fromRawKey as hmacFromRawKey} from './hmac';
+import * as Validators from './validators';
/**
* Computes an HKDF.
*
- * @param {number} size The length of the generated pseudorandom string in
+ * @param size The length of the generated pseudorandom string in
* bytes. The maximal size is 255 * DigestSize, where DigestSize is the size
* of the underlying HMAC.
- * @param {string} hash the name of the hash function. Accepted names are SHA-1,
+ * @param hash the name of the hash function. Accepted names are SHA-1,
* SHA-256 and SHA-512
- * @param {!Uint8Array} ikm Input keying material.
- * @param {!Uint8Array} info Context and application specific
+ * @param ikm Input keying material.
+ * @param info Context and application specific
* information (can be a zero-length array).
- * @param {!Uint8Array=} opt_salt Salt value (a non-secret random
+ * @param opt_salt Salt value (a non-secret random
* value). If not provided, it is set to a string of hash length zeros.
- * @return {!Promise.<!Uint8Array>} Output keying material (okm).
+ * @return Output keying material (okm).
*/
-const compute = async function(size, hash, ikm, info, opt_salt) {
+export async function compute(
+ size: number, hash: string, ikm: Uint8Array, info: Uint8Array,
+ opt_salt?: Uint8Array): Promise<Uint8Array> {
let digestSize;
if (!Number.isInteger(size)) {
throw new InvalidArgumentsException('size must be an integer');
@@ -67,10 +64,8 @@
default:
throw new InvalidArgumentsException(hash + ' is not supported');
}
-
Validators.requireUint8Array(ikm);
Validators.requireUint8Array(info);
-
let salt = opt_salt;
if (opt_salt == null || salt === undefined || salt.length == 0) {
salt = new Uint8Array(digestSize);
@@ -78,17 +73,19 @@
Validators.requireUint8Array(salt);
// Extract.
- let hmac = await Hmac.newInstance(hash, salt, digestSize);
- const prk = await hmac.computeMac(ikm); // Pseudorandom Key
+ let hmac = await hmacFromRawKey(hash, salt, digestSize);
+ const prk = await hmac.computeMac(
+ // Pseudorandom Key
+ ikm);
// Expand
- hmac = await Hmac.newInstance(hash, prk, digestSize);
+ hmac = await hmacFromRawKey(hash, prk, digestSize);
let ctr = 1;
let pos = 0;
let digest = new Uint8Array(0);
- let result = new Uint8Array(size);
+ const result = new Uint8Array(size);
while (true) {
- let input = new Uint8Array(digest.length + info.length + 1);
+ const input = new Uint8Array(digest.length + info.length + 1);
input.set(digest, 0);
input.set(info, digest.length);
input[input.length - 1] = ctr;
@@ -103,8 +100,4 @@
}
}
return result;
-};
-
-exports = {
- compute,
-};
+}
diff --git a/javascript/subtle/hkdf_test.js b/javascript/subtle/hkdf_test.js
index 8e98007..8dd443d 100644
--- a/javascript/subtle/hkdf_test.js
+++ b/javascript/subtle/hkdf_test.js
@@ -15,9 +15,9 @@
goog.module('tink.subtle.HkdfTest');
goog.setTestOnly('tink.subtle.HkdfTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Hkdf = goog.require('tink.subtle.Hkdf');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Hkdf = goog.require('google3.third_party.tink.javascript.subtle.hkdf');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
describe('hkdf test', function() {
it('constructor', async function() {
diff --git a/javascript/subtle/hmac.js b/javascript/subtle/hmac.js
deleted file mode 100644
index 42a8e66..0000000
--- a/javascript/subtle/hmac.js
+++ /dev/null
@@ -1,125 +0,0 @@
-// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.Hmac');
-
-const Bytes = goog.require('tink.subtle.Bytes');
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
-const Validators = goog.require('tink.subtle.Validators');
-
-/**
- * The minimum tag size.
- *
- * @const {number}
- */
-const MIN_TAG_SIZE_IN_BYTES = 10;
-
-/**
- * Implementation of HMAC.
- *
- * @public
- * @final
- */
-class Hmac extends Mac {
- /**
- * @param {string} hash accepted names are SHA-1, SHA-256 and SHA-512
- * @param {!webCrypto.CryptoKey} key
- * @param {number} tagSize the size of the tag
- */
- constructor(hash, key, tagSize) {
- super();
-
- /** @const @private {string} */
- this.hash_ = hash;
-
- /** @const @private {number} */
- this.tagSize_ = tagSize;
-
- /** @const @private {!webCrypto.CryptoKey} */
- this.key_ = key;
- }
-
- /**
- * @param {string} hash accepted names are SHA-1, SHA-256 and SHA-512
- * @param {!Uint8Array} key
- * @param {number} tagSize the size of the tag
- * @return {!Promise.<!Mac>}
- * @static
- */
- static async newInstance(hash, key, tagSize) {
- Validators.requireUint8Array(key);
- if (!Number.isInteger(tagSize)) {
- throw new InvalidArgumentsException(
- 'invalid tag size, must be an integer');
- }
- if (tagSize < MIN_TAG_SIZE_IN_BYTES) {
- throw new InvalidArgumentsException(
- 'tag too short, must be at least ' + MIN_TAG_SIZE_IN_BYTES +
- ' bytes');
- }
- switch (hash) {
- case 'SHA-1':
- if (tagSize > 20) {
- throw new InvalidArgumentsException(
- 'tag too long, must not be larger than 20 bytes');
- }
- break;
- case 'SHA-256':
- if (tagSize > 32) {
- throw new InvalidArgumentsException(
- 'tag too long, must not be larger than 32 bytes');
- }
- break;
- case 'SHA-512':
- if (tagSize > 64) {
- throw new InvalidArgumentsException(
- 'tag too long, must not be larger than 64 bytes');
- }
- break;
- default:
- throw new InvalidArgumentsException(hash + ' is not supported');
- }
-
- // TODO(b/115974209): Add check that key.length > 16.
-
- const cryptoKey = await self.crypto.subtle.importKey(
- 'raw', key,
- {'name': 'HMAC', 'hash': {'name': hash}, 'length': key.length * 8},
- false, ['sign', 'verify']);
- return new Hmac(hash, cryptoKey, tagSize);
- }
-
- /**
- * @override
- */
- async computeMac(data) {
- Validators.requireUint8Array(data);
- const tag = await self.crypto.subtle.sign(
- {'name': 'HMAC', 'hash': {'name': this.hash_}}, this.key_, data);
- return new Uint8Array(tag.slice(0, this.tagSize_));
- }
-
- /**
- * @override
- */
- async verifyMac(tag, data) {
- Validators.requireUint8Array(tag);
- Validators.requireUint8Array(data);
- const computedTag = await this.computeMac(data);
- return Bytes.isEqual(tag, computedTag);
- }
-}
-
-exports = Hmac;
diff --git a/javascript/subtle/hmac.ts b/javascript/subtle/hmac.ts
new file mode 100644
index 0000000..5452075
--- /dev/null
+++ b/javascript/subtle/hmac.ts
@@ -0,0 +1,101 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+////////////////////////////////////////////////////////////////////////////////
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
+import {Mac} from '../mac/internal/mac';
+
+import * as Bytes from './bytes';
+import * as Validators from './validators';
+
+/**
+ * The minimum tag size.
+ *
+ */
+const MIN_TAG_SIZE_IN_BYTES: number = 10;
+
+/**
+ * Implementation of HMAC.
+ *
+ * @final
+ */
+export class Hmac implements Mac {
+ /**
+ * @param hash accepted names are SHA-1, SHA-256 and SHA-512
+ * @param tagSize the size of the tag
+ */
+ constructor(
+ private readonly hash: string, private readonly key: CryptoKey,
+ private readonly tagSize: number) {}
+
+ /**
+ * @override
+ */
+ async computeMac(data: Uint8Array): Promise<Uint8Array> {
+ Validators.requireUint8Array(data);
+ const tag = await self.crypto.subtle.sign(
+ {'name': 'HMAC', 'hash': {'name': this.hash}}, this.key, data);
+ return new Uint8Array(tag.slice(0, this.tagSize));
+ }
+
+ /**
+ * @override
+ */
+ async verifyMac(tag: Uint8Array, data: Uint8Array): Promise<boolean> {
+ Validators.requireUint8Array(tag);
+ Validators.requireUint8Array(data);
+ const computedTag = await this.computeMac(data);
+ return Bytes.isEqual(tag, computedTag);
+ }
+}
+
+/**
+ * @param hash accepted names are SHA-1, SHA-256 and SHA-512
+ * @param tagSize the size of the tag
+ */
+export async function fromRawKey(
+ hash: string, key: Uint8Array, tagSize: number): Promise<Mac> {
+ Validators.requireUint8Array(key);
+ if (!Number.isInteger(tagSize)) {
+ throw new InvalidArgumentsException('invalid tag size, must be an integer');
+ }
+ if (tagSize < MIN_TAG_SIZE_IN_BYTES) {
+ throw new InvalidArgumentsException(
+ 'tag too short, must be at least ' + MIN_TAG_SIZE_IN_BYTES + ' bytes');
+ }
+ switch (hash) {
+ case 'SHA-1':
+ if (tagSize > 20) {
+ throw new InvalidArgumentsException(
+ 'tag too long, must not be larger than 20 bytes');
+ }
+ break;
+ case 'SHA-256':
+ if (tagSize > 32) {
+ throw new InvalidArgumentsException(
+ 'tag too long, must not be larger than 32 bytes');
+ }
+ break;
+ case 'SHA-512':
+ if (tagSize > 64) {
+ throw new InvalidArgumentsException(
+ 'tag too long, must not be larger than 64 bytes');
+ }
+ break;
+ default:
+ throw new InvalidArgumentsException(hash + ' is not supported');
+ }
+
+ // TODO(b/115974209): Add check that key.length > 16.
+ const cryptoKey = await self.crypto.subtle.importKey(
+ 'raw', key,
+ {'name': 'HMAC', 'hash': {'name': hash}, 'length': key.length * 8}, false,
+ ['sign', 'verify']);
+ return new Hmac(hash, cryptoKey, tagSize);
+}
diff --git a/javascript/subtle/hmac_test.js b/javascript/subtle/hmac_test.js
index f391652..f489fd1 100644
--- a/javascript/subtle/hmac_test.js
+++ b/javascript/subtle/hmac_test.js
@@ -15,15 +15,15 @@
goog.module('tink.subtle.HmacTest');
goog.setTestOnly('tink.subtle.HmacTest');
-const Bytes = goog.require('tink.subtle.Bytes');
-const Hmac = goog.require('tink.subtle.Hmac');
-const Random = goog.require('tink.subtle.Random');
+const Bytes = goog.require('google3.third_party.tink.javascript.subtle.bytes');
+const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
+const {fromRawKey: hmacFromRawKey} = goog.require('google3.third_party.tink.javascript.subtle.hmac');
describe('hmac test', function() {
it('basic', async function() {
const key = Random.randBytes(16);
const msg = Random.randBytes(4);
- const hmac = await Hmac.newInstance('SHA-1', key, 10);
+ const hmac = await hmacFromRawKey('SHA-1', key, 10);
const tag = await hmac.computeMac(msg);
expect(tag.length).toBe(10);
expect(await hmac.verifyMac(tag, msg)).toBe(true);
@@ -31,7 +31,7 @@
it('constructor', async function() {
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'blah', Random.randBytes(16), 16); // invalid HMAC algo name
fail('Should throw an exception.');
} catch (e) {
@@ -40,7 +40,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-1', Random.randBytes(15), 16); // invalid key size
// TODO(b/115974209): This case does not throw an exception.
} catch (e) {
@@ -49,7 +49,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-1', Random.randBytes(16), 9); // tag size too short
fail('Should throw an exception.');
} catch (e) {
@@ -58,7 +58,7 @@
'InvalidArgumentsException: tag too short, must be at least 10 bytes');
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-1', Random.randBytes(16), 21); // tag size too long
fail('Should throw an exception.');
} catch (e) {
@@ -68,7 +68,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-256', Random.randBytes(15), 16); // invalid key size
// TODO(b/115974209): This case does not throw an exception.
} catch (e) {
@@ -77,7 +77,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-256', Random.randBytes(16), 9); // tag size too short
fail('Should throw an exception.');
} catch (e) {
@@ -87,7 +87,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-256', Random.randBytes(16), 33); // tag size too long
fail('Should throw an exception.');
} catch (e) {
@@ -97,7 +97,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-512', Random.randBytes(15), 16); // invalid key size
// TODO(b/115974209): This case does not throw an exception.
} catch (e) {
@@ -106,7 +106,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-512', Random.randBytes(16), 9); // tag size too short
fail('Should throw an exception.');
} catch (e) {
@@ -116,7 +116,7 @@
}
try {
- await Hmac.newInstance(
+ await hmacFromRawKey(
'SHA-512', Random.randBytes(16), 65); // tag size too long
fail('Should throw an exception.');
} catch (e) {
@@ -128,7 +128,7 @@
it('constructor, invalid tag sizes', async function() {
try {
- await Hmac.newInstance('SHA-512', Random.randBytes(16), NaN);
+ await hmacFromRawKey('SHA-512', Random.randBytes(16), NaN);
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -137,7 +137,7 @@
}
try {
- await Hmac.newInstance('SHA-512', Random.randBytes(16), 12.5);
+ await hmacFromRawKey('SHA-512', Random.randBytes(16), 12.5);
fail('Should throw an exception.');
} catch (e) {
expect(e.toString())
@@ -149,7 +149,7 @@
it('modify', async function() {
const key = Random.randBytes(16);
const msg = Random.randBytes(8);
- const hmac = await Hmac.newInstance('SHA-1', key, 20);
+ const hmac = await hmacFromRawKey('SHA-1', key, 20);
const tag = await hmac.computeMac(msg);
// Modify tag.
@@ -216,7 +216,7 @@
const key = Bytes.fromHex(testVector['key']);
const message = Bytes.fromHex(testVector['message']);
const tag = Bytes.fromHex(testVector['tag']);
- const hmac = await Hmac.newInstance(testVector['algo'], key, tag.length);
+ const hmac = await hmacFromRawKey(testVector['algo'], key, tag.length);
expect(await hmac.verifyMac(tag, message)).toBe(true);
}
});
diff --git a/javascript/subtle/ind_cpa_cipher.js b/javascript/subtle/ind_cpa_cipher.ts
similarity index 68%
rename from javascript/subtle/ind_cpa_cipher.js
rename to javascript/subtle/ind_cpa_cipher.ts
index a0dd0ca..55961ab 100644
--- a/javascript/subtle/ind_cpa_cipher.js
+++ b/javascript/subtle/ind_cpa_cipher.ts
@@ -1,21 +1,14 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
-goog.module('tink.subtle.IndCpaCipher');
-
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
/**
* Interface for symmetric key ciphers that are indistinguishable against
* chosen-plaintext attacks.
@@ -24,29 +17,25 @@
* authentication, thus should not be used directly, but only to construct safer
* primitives such as {@link tink.Aead}.
*
- * @protected
- * @record
*/
-class IndCpaCipher {
+export interface IndCpaCipher {
/**
* Encrypts `plaintext`.
*
- * @param {!Uint8Array} plaintext the plaintext to be encrypted. It must be
+ * @param plaintext the plaintext to be encrypted. It must be
* non-null, but can also be an empty (zero-length) byte array.
- * @return {!Promise.<!Uint8Array>} resulting ciphertext
+ * @return resulting ciphertext
* @throws {SecurityException}
*/
- encrypt(plaintext) {}
+ encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
/**
* Decrypts ciphertext with associated authenticated data.
*
- * @param {!Uint8Array} ciphertext the ciphertext to be decrypted, must be
+ * @param ciphertext the ciphertext to be decrypted, must be
* non-null.
- * @return {!Promise.<!Uint8Array>} resulting plaintext
+ * @return resulting plaintext
* @throws {SecurityException}
*/
- decrypt(ciphertext) {}
+ decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
}
-
-exports = IndCpaCipher;
diff --git a/javascript/subtle/random.js b/javascript/subtle/random.ts
similarity index 74%
rename from javascript/subtle/random.js
rename to javascript/subtle/random.ts
index ae478d8..ecd890c 100644
--- a/javascript/subtle/random.js
+++ b/javascript/subtle/random.ts
@@ -1,40 +1,31 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
/**
* @fileoverview Several simple wrappers of crypto.getRandomValues.
- * @public
*/
-
-goog.module('tink.subtle.Random');
-
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
/**
* Randomly generates `n` bytes.
*
- * @param {number} n number of bytes to generate
- * @return {!Uint8Array} the random bytes
+ * @param n number of bytes to generate
+ * @return the random bytes
* @static
*/
-const randBytes = function(n) {
+export function randBytes(n: number): Uint8Array {
if (!Number.isInteger(n) || n < 0) {
throw new InvalidArgumentsException('n must be a nonnegative integer');
}
const result = new Uint8Array(n);
crypto.getRandomValues(result);
return result;
-};
-
-exports = {randBytes};
+}
diff --git a/javascript/subtle/validators.js b/javascript/subtle/validators.ts
similarity index 71%
rename from javascript/subtle/validators.js
rename to javascript/subtle/validators.ts
index 76eac26..dd0c161 100644
--- a/javascript/subtle/validators.js
+++ b/javascript/subtle/validators.ts
@@ -1,79 +1,66 @@
// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
////////////////////////////////////////////////////////////////////////////////
-
-goog.module('tink.subtle.Validators');
-
-const {InvalidArgumentsException} = goog.require('google3.third_party.tink.javascript.exception.invalid_arguments_exception');
-const {SecurityException} = goog.require('google3.third_party.tink.javascript.exception.security_exception');
-
-/**
- * @const @public {!Array.<number>}
- */
-const SUPPORTED_AES_KEY_SIZES = [16, 32];
+import {InvalidArgumentsException} from '../exception/invalid_arguments_exception';
+import {SecurityException} from '../exception/security_exception';
+const SUPPORTED_AES_KEY_SIZES: number[] = [16, 32];
/**
* Validates AES key sizes, at the moment only 128-bit and 256-bit keys are
* supported.
*
- * @param {number} n the key size in bytes
+ * @param n the key size in bytes
* @throws {!InvalidArgumentsException}
* @static
*/
-const validateAesKeySize = function(n) {
+export function validateAesKeySize(n: number) {
if (!SUPPORTED_AES_KEY_SIZES.includes(n)) {
throw new InvalidArgumentsException('unsupported AES key size: ' + n);
}
-};
+}
/**
* Validates that the input is a non null Uint8Array.
*
- * @param {!Uint8Array} input
* @throws {!InvalidArgumentsException}
* @static
*/
-const requireUint8Array = function(input) {
+export function requireUint8Array(input: Uint8Array) {
if (input == null || !(input instanceof Uint8Array)) {
throw new InvalidArgumentsException('input must be a non null Uint8Array');
}
-};
+}
/**
* Validates version, throws exception if candidate version is negative or
* bigger than expected.
*
- * @param {number} candidate - version to be validated
- * @param {number} maxVersion - upper bound on version
+ * @param candidate - version to be validated
+ * @param maxVersion - upper bound on version
* @throws {!SecurityException}
* @static
*/
-const validateVersion = function(candidate, maxVersion) {
+export function validateVersion(candidate: number, maxVersion: number) {
if (candidate < 0 || candidate > maxVersion) {
throw new SecurityException(
'Version is out of bound, must be ' +
'between 0 and ' + maxVersion + '.');
}
-};
+}
/**
* Validates ECDSA parameters.
*
- * @param {string} curve
- * @param {string} hash
* @throws {!SecurityException}
*/
-const validateEcdsaParams = function(curve, hash) {
+export function validateEcdsaParams(curve: string, hash: string) {
switch (curve) {
case 'P-256':
if (hash != 'SHA-256') {
@@ -97,11 +84,4 @@
default:
throw new SecurityException('unsupported curve: ' + curve);
}
-};
-
-exports = {
- validateAesKeySize,
- validateEcdsaParams,
- requireUint8Array,
- validateVersion
-};
+}
diff --git a/javascript/testing/index.ts b/javascript/testing/index.ts
index 5cca6a8..a92ac5c 100644
--- a/javascript/testing/index.ts
+++ b/javascript/testing/index.ts
@@ -1,3 +1,3 @@
-import Registry from 'goog:tink.Registry'; // from //third_party/tink/javascript:registry_legacy
+import * as Registry from '../internal/registry';
export const resetRegistry = Registry.reset;
diff --git a/kokoro/continuous.sh b/kokoro/continuous.sh
index 4fcaca0..4c93061 100755
--- a/kokoro/continuous.sh
+++ b/kokoro/continuous.sh
@@ -26,9 +26,6 @@
source ./kokoro/run_tests.sh
-# Test that Tink can be installed with the standard Go tooling.
-go get github.com/google/tink/go/...
-
# Run all manual tests.
(
cd java_src
diff --git a/kokoro/gcp_ubuntu_per_language/cross_language/common.cfg b/kokoro/gcp_ubuntu_per_language/cross_language/common.cfg
new file mode 100644
index 0000000..9bae2a8
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/cross_language/common.cfg
@@ -0,0 +1,3 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "tink/kokoro/gcp_ubuntu_per_language/cross_language/run_tests.sh"
diff --git a/kokoro/gcp_ubuntu_per_language/go/continuous.cfg b/kokoro/gcp_ubuntu_per_language/cross_language/continuous.cfg
similarity index 100%
copy from kokoro/gcp_ubuntu_per_language/go/continuous.cfg
copy to kokoro/gcp_ubuntu_per_language/cross_language/continuous.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/go/presubmit.cfg b/kokoro/gcp_ubuntu_per_language/cross_language/presubmit.cfg
similarity index 100%
copy from kokoro/gcp_ubuntu_per_language/go/presubmit.cfg
copy to kokoro/gcp_ubuntu_per_language/cross_language/presubmit.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/cross_language/run_tests.sh b/kokoro/gcp_ubuntu_per_language/cross_language/run_tests.sh
new file mode 100644
index 0000000..0a23bd1
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/cross_language/run_tests.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+set -euo pipefail
+
+CURRENT_BAZEL_VERSION=""
+
+install_python3() {
+ : "${PYTHON_VERSION:=3.7.1}"
+
+ # Update python version list.
+ (
+ cd /home/kbuilder/.pyenv/plugins/python-build/../..
+ git pull
+ )
+ # Install Python.
+ eval "$(pyenv init -)"
+ pyenv install -v "${PYTHON_VERSION}"
+ pyenv global "${PYTHON_VERSION}"
+}
+
+use_bazel() {
+ local candidate_version="$1"
+ if [[ "${candidate_version}" != "${CURRENT_BAZEL_VERSION}" ]]; then
+ CURRENT_BAZEL_VERSION="${candidate_version}"
+ if [[ -n "${KOKORO_ROOT:-}" ]] ; then
+ use_bazel.sh "${candidate_version}"
+ else
+ bazel --version
+ fi
+ fi
+}
+
+main() {
+ if [[ -n "${KOKORO_ROOT:-}" ]] ; then
+ install_python3
+ cd "${KOKORO_ARTIFACTS_DIR}/git/tink"
+ fi
+ (
+ cd testing/cc
+ use_bazel "$(cat .bazelversion)"
+ time bazel build -- ...
+ time bazel test --test_output=errors -- ...
+ )
+ (
+ cd testing/go
+ use_bazel "$(cat .bazelversion)"
+ time bazel build -- ...
+ time bazel test --test_output=errors -- ...
+ )
+ (
+ cd testing/java_src
+ use_bazel "$(cat .bazelversion)"
+ time bazel build -- ...
+ time bazel build :testing_server_deploy.jar
+ time bazel test --test_output=errors -- ...
+ )
+ (
+ cd testing/python
+ use_bazel "$(cat .bazelversion)"
+ time bazel build -- ...
+ time bazel test --test_output=errors -- ...
+ )
+
+ local testing_dir="${PWD}/testing"
+ (
+ cd testing/cross_language
+ use_bazel "$(cat .bazelversion)"
+ time bazel test \
+ --test_env testing_dir="${testing_dir}" --test_output=errors -- ...
+ )
+}
+
+main "$@"
diff --git a/kokoro/gcp_ubuntu_per_language/go/bazel/common.cfg b/kokoro/gcp_ubuntu_per_language/go/bazel/common.cfg
new file mode 100644
index 0000000..f8f42eb
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/go/bazel/common.cfg
@@ -0,0 +1,3 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "tink/kokoro/gcp_ubuntu_per_language/go/bazel/run_tests.sh"
diff --git a/kokoro/gcp_ubuntu_per_language/go/continuous.cfg b/kokoro/gcp_ubuntu_per_language/go/bazel/continuous.cfg
similarity index 100%
rename from kokoro/gcp_ubuntu_per_language/go/continuous.cfg
rename to kokoro/gcp_ubuntu_per_language/go/bazel/continuous.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/go/presubmit.cfg b/kokoro/gcp_ubuntu_per_language/go/bazel/presubmit.cfg
similarity index 100%
rename from kokoro/gcp_ubuntu_per_language/go/presubmit.cfg
rename to kokoro/gcp_ubuntu_per_language/go/bazel/presubmit.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/go/bazel/run_tests.sh b/kokoro/gcp_ubuntu_per_language/go/bazel/run_tests.sh
new file mode 100644
index 0000000..b845951
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/go/bazel/run_tests.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -euo pipefail
+
+cd "${KOKORO_ARTIFACTS_DIR}/git/tink/go"
+use_bazel.sh "$(cat .bazelversion)"
+time bazel build -- ...
+time bazel test -- ...
diff --git a/kokoro/gcp_ubuntu_per_language/go/common.cfg b/kokoro/gcp_ubuntu_per_language/go/common.cfg
deleted file mode 100644
index 63fb24c..0000000
--- a/kokoro/gcp_ubuntu_per_language/go/common.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-build_file: "tink/kokoro/gcp_ubuntu_per_language/go/run_tests.sh"
diff --git a/kokoro/gcp_ubuntu_per_language/go/gomod/common.cfg b/kokoro/gcp_ubuntu_per_language/go/gomod/common.cfg
new file mode 100644
index 0000000..7d31099
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/go/gomod/common.cfg
@@ -0,0 +1,3 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "tink/kokoro/gcp_ubuntu_per_language/go/gomod/run_tests.sh"
diff --git a/kokoro/gcp_ubuntu_per_language/go/continuous.cfg b/kokoro/gcp_ubuntu_per_language/go/gomod/continuous.cfg
similarity index 100%
copy from kokoro/gcp_ubuntu_per_language/go/continuous.cfg
copy to kokoro/gcp_ubuntu_per_language/go/gomod/continuous.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/go/presubmit.cfg b/kokoro/gcp_ubuntu_per_language/go/gomod/presubmit.cfg
similarity index 100%
copy from kokoro/gcp_ubuntu_per_language/go/presubmit.cfg
copy to kokoro/gcp_ubuntu_per_language/go/gomod/presubmit.cfg
diff --git a/kokoro/gcp_ubuntu_per_language/go/gomod/run_tests.sh b/kokoro/gcp_ubuntu_per_language/go/gomod/run_tests.sh
new file mode 100644
index 0000000..fe4c12d
--- /dev/null
+++ b/kokoro/gcp_ubuntu_per_language/go/gomod/run_tests.sh
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+set -euo pipefail
+
+REPO_DIR="${KOKORO_ARTIFACTS_DIR}/git/tink"
+
+TINK_VERSION="$(cat ${REPO_DIR}/tink_version.bzl | grep ^TINK | cut -f 2 -d \")"
+
+# Create a temporary directory for performing module tests.
+TMP_DIR="$(mktemp -dt go-module-test.XXXXXX)"
+GO_MOD_DIR="${TMP_DIR}/go-mod-test"
+
+REPO_URL_PREFIX="github.com/google/tink"
+
+#######################################
+# Test an individual Go module within the Tink repository.
+# Globals:
+# REPO_DIR
+# TINK_VERISON
+# GO_MOD_DIR
+# REPO_URL_PREFIX
+# Arguments:
+# The name of the Go module, relative to the repository root.
+# Outputs:
+# Prints progress to STDOUT.
+#######################################
+function test_go_mod() {
+ local mod_name="$1"
+ local full_mod_name="${REPO_URL_PREFIX}/${mod_name}"
+
+ echo "### Testing ${full_mod_name}..."
+ mkdir "${GO_MOD_DIR}"
+ (
+ cd "${GO_MOD_DIR}"
+
+ # Display commands being run for the remainder of this subshell.
+ set -x
+
+ # Initialize a test Go module.
+ go mod init tink-go-mod-test
+ overlay_module "${mod_name}" "${full_mod_name}"
+ overlay_internal_deps "${mod_name}"
+
+ # Print the prepared go.mod.
+ cat go.mod
+
+ # Get the module at the latest commit and print graph output depicting
+ # direct dependencies.
+ go get -v "${full_mod_name}@master"
+
+ # Pint contextual information concerning dependencies.
+ go mod graph | grep google/tink
+ go list -m all | grep google/tink
+ )
+
+ # Leave a clean environment for subsequent tests.
+ go clean -modcache
+ rm -rf "${GO_MOD_DIR}"
+}
+
+#######################################
+# Add a require statement for a Tink module and a replace statement to point it
+# to the local copy.
+# Globals:
+# REPO_DIR
+# TINK_VERISON
+# Arguments:
+# The name of the Go module, relative to the repository root.
+# The full name of the Go module, as specified in import statements.
+#######################################
+function overlay_module() {
+ local mod_name="$1"
+ local full_mod_name="$2"
+
+ go mod edit "-require=${full_mod_name}@v${TINK_VERSION}"
+ go mod edit "-replace=${full_mod_name}=${REPO_DIR}/${mod_name}"
+}
+
+#######################################
+# Search the go.mod being tested for internal dependencies and overlay them with
+# the local copies.
+# Globals:
+# REPO_DIR
+# REPO_URL_PREFIX
+# Arguments:
+# The name of the Go module being tested, relative to the repository root.
+#######################################
+function overlay_internal_deps() {
+ local mod_name="$1"
+
+ declare -a internal_deps
+ while read internal_dep; do
+ internal_deps+=("${internal_dep}")
+ done < <(grep "${REPO_URL_PREFIX}" "${REPO_DIR}/${mod_name}/go.mod" \
+ | grep -v ^module \
+ | awk '{print $1}')
+
+ # If internal_deps are found...
+ if [[ ! -z "${internal_deps+x}" ]]; then
+ for full_dep_name in "${internal_deps[@]}"; do
+ local dep_name="$(echo "${full_dep_name}" | sed "s#${REPO_URL_PREFIX}/##")"
+ overlay_module "${dep_name}" "${full_dep_name}"
+ done
+ fi
+}
+
+function main() {
+ # Extract all go.mod instances from the repository.
+ declare -a go_mod_dirs
+ while read go_mod_dir; do
+ go_mod_dirs+=("${go_mod_dir}")
+ done < <(find "${REPO_DIR}" -name "go.mod" \
+ | sed "s#^${REPO_DIR}/##" \
+ | xargs -n 1 dirname)
+
+ echo "### Go modules found:"
+ for go_mod_dir in "${go_mod_dirs[@]}"; do
+ echo "${go_mod_dir}"
+ done
+
+ for go_mod_dir in "${go_mod_dirs[@]}"; do
+ test_go_mod "${go_mod_dir}"
+ done
+}
+
+main "$@"
diff --git a/kokoro/gcp_ubuntu_per_language/go/run_tests.sh b/kokoro/gcp_ubuntu_per_language/go/run_tests.sh
deleted file mode 100644
index a7d127d..0000000
--- a/kokoro/gcp_ubuntu_per_language/go/run_tests.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-set -euo pipefail
-cd ${KOKORO_ARTIFACTS_DIR}/git/tink
-
-cd go
-use_bazel.sh $(cat .bazelversion)
-time bazel build -- ...
-time bazel test -- ...
diff --git a/kokoro/gcp_ubuntu_per_language/python/pip/run_tests.sh b/kokoro/gcp_ubuntu_per_language/python/pip/run_tests.sh
index 606a7c4..9bf6571 100644
--- a/kokoro/gcp_ubuntu_per_language/python/pip/run_tests.sh
+++ b/kokoro/gcp_ubuntu_per_language/python/pip/run_tests.sh
@@ -1,8 +1,7 @@
#!/bin/bash
set -euo pipefail
-cd ${KOKORO_ARTIFACTS_DIR}/git/tink
-
+cd ${KOKORO_ARTIFACTS_DIR}/git/tink/python
install_python3() {
: "${PYTHON_VERSION:=3.7.1}"
@@ -17,11 +16,8 @@
pyenv global "${PYTHON_VERSION}"
}
-
install_pip_package() {
# Check if we can build Tink python package.
- (
- cd python
# Needed for setuptools
use_bazel.sh $(cat .bazelversion)
@@ -29,12 +25,28 @@
PROTOC_ZIP='protoc-3.11.4-linux-x86_64.zip'
curl -OL "https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/${PROTOC_ZIP}"
sudo unzip -o "${PROTOC_ZIP}" -d /usr/local bin/protoc
+
+ # Set path to Tink base folder
+ export TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH=$PWD/..
+
# Update pip and start setup
pip3 install --upgrade pip
pip3 install --upgrade setuptools
pip3 install .
- )
}
+run_tests_with_package() {
+ # Set path to Tink base folder
+ export TINK_SRC_PATH=${PWD}/..
+
+ # Run Python tests directly so the package is used.
+ # We exclude tests in tink/cc/pybind: they are implementation details and may
+ # depend on a testonly shared object.
+ find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 | xargs -0 -n1 python3
+}
install_python3
install_pip_package
+run_tests_with_package
+
+# Generate release of the pip package and test it
+./tools/distribution/create_release.sh
diff --git a/kokoro/macos_external/go/bazel/common.cfg b/kokoro/macos_external/go/bazel/common.cfg
new file mode 100644
index 0000000..58de5cd
--- /dev/null
+++ b/kokoro/macos_external/go/bazel/common.cfg
@@ -0,0 +1,3 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "tink/kokoro/macos_external/go/bazel/run_tests.sh"
diff --git a/kokoro/macos_external/go/continuous.cfg b/kokoro/macos_external/go/bazel/continuous.cfg
similarity index 100%
rename from kokoro/macos_external/go/continuous.cfg
rename to kokoro/macos_external/go/bazel/continuous.cfg
diff --git a/kokoro/macos_external/go/presubmit.cfg b/kokoro/macos_external/go/bazel/presubmit.cfg
similarity index 100%
rename from kokoro/macos_external/go/presubmit.cfg
rename to kokoro/macos_external/go/bazel/presubmit.cfg
diff --git a/kokoro/macos_external/go/bazel/run_tests.sh b/kokoro/macos_external/go/bazel/run_tests.sh
new file mode 100644
index 0000000..b845951
--- /dev/null
+++ b/kokoro/macos_external/go/bazel/run_tests.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -euo pipefail
+
+cd "${KOKORO_ARTIFACTS_DIR}/git/tink/go"
+use_bazel.sh "$(cat .bazelversion)"
+time bazel build -- ...
+time bazel test -- ...
diff --git a/kokoro/macos_external/go/common.cfg b/kokoro/macos_external/go/common.cfg
deleted file mode 100644
index 5d05f0b..0000000
--- a/kokoro/macos_external/go/common.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-build_file: "tink/kokoro/macos_external/go/run_tests.sh"
diff --git a/kokoro/macos_external/go/gomod/common.cfg b/kokoro/macos_external/go/gomod/common.cfg
new file mode 100644
index 0000000..ee085b3
--- /dev/null
+++ b/kokoro/macos_external/go/gomod/common.cfg
@@ -0,0 +1,3 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "tink/kokoro/macos_external/go/gomod/run_tests.sh"
diff --git a/kokoro/macos_external/go/continuous.cfg b/kokoro/macos_external/go/gomod/continuous.cfg
similarity index 100%
copy from kokoro/macos_external/go/continuous.cfg
copy to kokoro/macos_external/go/gomod/continuous.cfg
diff --git a/kokoro/macos_external/go/presubmit.cfg b/kokoro/macos_external/go/gomod/presubmit.cfg
similarity index 100%
copy from kokoro/macos_external/go/presubmit.cfg
copy to kokoro/macos_external/go/gomod/presubmit.cfg
diff --git a/kokoro/macos_external/go/gomod/run_tests.sh b/kokoro/macos_external/go/gomod/run_tests.sh
new file mode 100644
index 0000000..fe4c12d
--- /dev/null
+++ b/kokoro/macos_external/go/gomod/run_tests.sh
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+set -euo pipefail
+
+REPO_DIR="${KOKORO_ARTIFACTS_DIR}/git/tink"
+
+TINK_VERSION="$(cat ${REPO_DIR}/tink_version.bzl | grep ^TINK | cut -f 2 -d \")"
+
+# Create a temporary directory for performing module tests.
+TMP_DIR="$(mktemp -dt go-module-test.XXXXXX)"
+GO_MOD_DIR="${TMP_DIR}/go-mod-test"
+
+REPO_URL_PREFIX="github.com/google/tink"
+
+#######################################
+# Test an individual Go module within the Tink repository.
+# Globals:
+# REPO_DIR
+# TINK_VERISON
+# GO_MOD_DIR
+# REPO_URL_PREFIX
+# Arguments:
+# The name of the Go module, relative to the repository root.
+# Outputs:
+# Prints progress to STDOUT.
+#######################################
+function test_go_mod() {
+ local mod_name="$1"
+ local full_mod_name="${REPO_URL_PREFIX}/${mod_name}"
+
+ echo "### Testing ${full_mod_name}..."
+ mkdir "${GO_MOD_DIR}"
+ (
+ cd "${GO_MOD_DIR}"
+
+ # Display commands being run for the remainder of this subshell.
+ set -x
+
+ # Initialize a test Go module.
+ go mod init tink-go-mod-test
+ overlay_module "${mod_name}" "${full_mod_name}"
+ overlay_internal_deps "${mod_name}"
+
+ # Print the prepared go.mod.
+ cat go.mod
+
+ # Get the module at the latest commit and print graph output depicting
+ # direct dependencies.
+ go get -v "${full_mod_name}@master"
+
+ # Pint contextual information concerning dependencies.
+ go mod graph | grep google/tink
+ go list -m all | grep google/tink
+ )
+
+ # Leave a clean environment for subsequent tests.
+ go clean -modcache
+ rm -rf "${GO_MOD_DIR}"
+}
+
+#######################################
+# Add a require statement for a Tink module and a replace statement to point it
+# to the local copy.
+# Globals:
+# REPO_DIR
+# TINK_VERISON
+# Arguments:
+# The name of the Go module, relative to the repository root.
+# The full name of the Go module, as specified in import statements.
+#######################################
+function overlay_module() {
+ local mod_name="$1"
+ local full_mod_name="$2"
+
+ go mod edit "-require=${full_mod_name}@v${TINK_VERSION}"
+ go mod edit "-replace=${full_mod_name}=${REPO_DIR}/${mod_name}"
+}
+
+#######################################
+# Search the go.mod being tested for internal dependencies and overlay them with
+# the local copies.
+# Globals:
+# REPO_DIR
+# REPO_URL_PREFIX
+# Arguments:
+# The name of the Go module being tested, relative to the repository root.
+#######################################
+function overlay_internal_deps() {
+ local mod_name="$1"
+
+ declare -a internal_deps
+ while read internal_dep; do
+ internal_deps+=("${internal_dep}")
+ done < <(grep "${REPO_URL_PREFIX}" "${REPO_DIR}/${mod_name}/go.mod" \
+ | grep -v ^module \
+ | awk '{print $1}')
+
+ # If internal_deps are found...
+ if [[ ! -z "${internal_deps+x}" ]]; then
+ for full_dep_name in "${internal_deps[@]}"; do
+ local dep_name="$(echo "${full_dep_name}" | sed "s#${REPO_URL_PREFIX}/##")"
+ overlay_module "${dep_name}" "${full_dep_name}"
+ done
+ fi
+}
+
+function main() {
+ # Extract all go.mod instances from the repository.
+ declare -a go_mod_dirs
+ while read go_mod_dir; do
+ go_mod_dirs+=("${go_mod_dir}")
+ done < <(find "${REPO_DIR}" -name "go.mod" \
+ | sed "s#^${REPO_DIR}/##" \
+ | xargs -n 1 dirname)
+
+ echo "### Go modules found:"
+ for go_mod_dir in "${go_mod_dirs[@]}"; do
+ echo "${go_mod_dir}"
+ done
+
+ for go_mod_dir in "${go_mod_dirs[@]}"; do
+ test_go_mod "${go_mod_dir}"
+ done
+}
+
+main "$@"
diff --git a/kokoro/macos_external/go/run_tests.sh b/kokoro/macos_external/go/run_tests.sh
deleted file mode 100644
index a7d127d..0000000
--- a/kokoro/macos_external/go/run_tests.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-set -euo pipefail
-cd ${KOKORO_ARTIFACTS_DIR}/git/tink
-
-cd go
-use_bazel.sh $(cat .bazelversion)
-time bazel build -- ...
-time bazel test -- ...
diff --git a/kokoro/macos_external/python/pip/run_tests.sh b/kokoro/macos_external/python/pip/run_tests.sh
index c74ce8b..b0322e7 100644
--- a/kokoro/macos_external/python/pip/run_tests.sh
+++ b/kokoro/macos_external/python/pip/run_tests.sh
@@ -15,6 +15,10 @@
PROTOC_ZIP=protoc-3.11.4-osx-x86_64.zip
curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/$PROTOC_ZIP
sudo unzip -o $PROTOC_ZIP -d /usr/local bin/protoc
+
+ # Set path to Tink base folder
+ export TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH=$PWD/..
+
# Update pip and install all requirements. Note that on MacOS we need to
# use the --user flag as otherwise pip will complain about permissions.
pip3 install --upgrade pip --user
@@ -23,4 +27,19 @@
)
}
+run_tests_with_package() {
+ # Get root certificates for gRPC
+ wget https://raw.githubusercontent.com/grpc/grpc/master/etc/roots.pem
+ export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=${PWD}/roots.pem
+
+ # Set path to Tink base folder
+ export TINK_SRC_PATH=${PWD}
+
+ # Run Python tests directly so the package is used.
+ # We exclude tests in tink/cc/pybind: they are implementation details and may
+ # depend on a testonly shared object.
+ find python/tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 | xargs -0 -n1 python3
+}
+
install_pip_package
+run_tests_with_package
diff --git a/kokoro/presubmit.sh b/kokoro/presubmit.sh
index 6f6135b..7a017c1 100755
--- a/kokoro/presubmit.sh
+++ b/kokoro/presubmit.sh
@@ -24,7 +24,4 @@
# Change to repo root
cd git*/tink
-# Test that Tink can be installed with the standard Go tooling.
-go get github.com/google/tink/go/...
-
./kokoro/run_tests.sh
diff --git a/maven/README.md b/maven/README.md
index 9085fdf..534b66a 100644
--- a/maven/README.md
+++ b/maven/README.md
@@ -2,14 +2,29 @@
Tink Java has 4 Maven artifacts, all are in the `com.google.crypto.tink` group.
-- `tink`: this is the core of Tink built for server side apps. It only depends
- on `org.json:json` and `com.google.protobuf:protobuf-java`.
-- `tink-android`: this is similar to `tink` but is built for Android apps. It
- only depends on `com.google.protobuf:protobuf-lite`.
-- `tink-awskms`: this is a plugin for the `tink` artifact that integrates Tink
- with AWS KMS.
-- `tink-gcpkms`: this is a plugin for the `tink` artifact that integrates Tink
- with GCP KMS.
+### `tink`
+
+The core of Tink built for server-side applications. It only depends on
+[`org.json:json`](https://search.maven.org/artifact/org.json/json) and
+[`com.google.protobuf:protobuf-java`](https://search.maven.org/artifact/com.google.protobuf/protobuf-java).
+
+### `tink-android`
+
+Similar to `tink` but is built for Android applicationss.
+
+This build includes an embeded copy
+[`com.google.protobuf:protobuf-lite`](https://search.maven.org/artifact/com.google.protobuf/protobuf-javalite),
+which is renamed to be `com.google.crypto.tink.shaded.protobuf`. This is done to
+avoid dependency conflicts with other common dependencies that depend on a
+conflicting version (e.g. Firebase).
+
+### `tink-awskms`
+
+A plugin for the `tink` artifact that integrates Tink with AWS KMS.
+
+### `tink-gcpkms`
+
+A plugin for the `tink` artifact that integrates Tink with GCP KMS.
## Publishing snapshots
@@ -20,8 +35,8 @@
This command publishes latest snapshots to Maven, and their Javadocs to
https://google.github.com/tink.
-Snapshots are also automatically published for every new commit to
-the master branch of https://github.com/google/tink.
+Snapshots are automatically published for every new commit to the master branch
+of https://github.com/google/tink.
## Testing snapshots
diff --git a/maven/execute-deploy.sh b/maven/execute-deploy.sh
index 93f4c32..1d309cc 100755
--- a/maven/execute-deploy.sh
+++ b/maven/execute-deploy.sh
@@ -218,7 +218,7 @@
deploy_library \
tink-android \
java_src \
- tink-android-shaded.jar \
+ tink-android.jar \
tink-android-src.jar \
tink-android-javadoc.jar \
"../$(dirname $0)/tink-android.pom.xml"
diff --git a/objc/Tests/UnitTests/aead/TINKAeadKeyTemplateTest.mm b/objc/Tests/UnitTests/aead/TINKAeadKeyTemplateTest.mm
index c764491..65c1251 100644
--- a/objc/Tests/UnitTests/aead/TINKAeadKeyTemplateTest.mm
+++ b/objc/Tests/UnitTests/aead/TINKAeadKeyTemplateTest.mm
@@ -24,13 +24,6 @@
#import "objc/TINKKeyTemplate.h"
#import "objc/core/TINKKeyTemplate_Internal.h"
-#import "objc/util/TINKProtoHelpers.h"
-#import "proto/AesCtr.pbobjc.h"
-#import "proto/AesCtrHmacAead.pbobjc.h"
-#import "proto/AesGcm.pbobjc.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/Hmac.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
using google::crypto::tink::XChaCha20Poly1305KeyFormat;
@@ -40,7 +33,7 @@
@implementation TINKAeadKeyTemplatesTest
- (void)testAesGcmKeyTemplates {
- static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.AesGcmKey";
+ static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.AesGcmKey";
NSError *error = nil;
// AES-128 GCM
@@ -49,41 +42,22 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBAesGcmKeyFormat *keyFormat =
- [TINKPBAesGcmKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertTrue(16 == keyFormat.keySize);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
// AES-256 GCM
tpl = [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes256Gcm error:&error];
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- keyFormat = [TINKPBAesGcmKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertTrue(32 == keyFormat.keySize);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testAesCtrHmacKeyTemplates {
- NSString *kTypeURL = @"type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey";
+ static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey";
// AES-128 CTR HMAC SHA-256
NSError *error = nil;
@@ -92,49 +66,22 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBAesCtrHmacAeadKeyFormat *keyFormat =
- [TINKPBAesCtrHmacAeadKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertTrue(16 == keyFormat.aesCtrKeyFormat.keySize);
- XCTAssertTrue(16 == keyFormat.aesCtrKeyFormat.params.ivSize);
- XCTAssertTrue(32 == keyFormat.hmacKeyFormat.keySize);
- XCTAssertTrue(16 == keyFormat.hmacKeyFormat.params.tagSize);
- XCTAssertTrue(TINKPBHashType_Sha256 == keyFormat.hmacKeyFormat.params.hash_p);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
// AES-256 CTR HMAC SHA-256
tpl = [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes256CtrHmacSha256 error:&error];
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- keyFormat = [TINKPBAesCtrHmacAeadKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertTrue(32 == keyFormat.aesCtrKeyFormat.keySize);
- XCTAssertTrue(16 == keyFormat.aesCtrKeyFormat.params.ivSize);
- XCTAssertTrue(32 == keyFormat.hmacKeyFormat.keySize);
- XCTAssertTrue(32 == keyFormat.hmacKeyFormat.params.tagSize);
- XCTAssertTrue(TINKPBHashType_Sha256 == keyFormat.hmacKeyFormat.params.hash_p);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testAesEaxKeyTemplates {
- static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.AesEaxKey";
+ static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.AesEaxKey";
NSError *error = nil;
// AES-128 EAX
@@ -143,41 +90,22 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBAesGcmKeyFormat *keyFormat =
- [TINKPBAesGcmKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertEqual(keyFormat.keySize, 16);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
// AES-256 EAX
tpl = [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes256Eax error:&error];
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- keyFormat = [TINKPBAesGcmKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertEqual(keyFormat.keySize, 32);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testXChaCha20Poly1305KeyTemplates {
- static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key";
+ static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key";
NSError *error = nil;
TINKAeadKeyTemplate *tpl = [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKXChaCha20Poly1305
@@ -185,22 +113,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
-
- // Check that the template works with the key manager.
- crypto::tink::XChaCha20Poly1305KeyManager key_manager;
- XCTAssertTrue(key_manager.get_key_type() == tpl.ccKeyTemplate->type_url());
- XChaCha20Poly1305KeyFormat key_format;
- XCTAssertTrue(key_format.ParseFromString(tpl.ccKeyTemplate->value()));
- auto validation = key_manager.ValidateKeyFormat(key_format);
- XCTAssertTrue(validation.ok());
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
@end
diff --git a/objc/Tests/UnitTests/core/TINKBinaryKeysetReaderTest.mm b/objc/Tests/UnitTests/core/TINKBinaryKeysetReaderTest.mm
index 04c613b..13d9534 100644
--- a/objc/Tests/UnitTests/core/TINKBinaryKeysetReaderTest.mm
+++ b/objc/Tests/UnitTests/core/TINKBinaryKeysetReaderTest.mm
@@ -21,7 +21,6 @@
#import <XCTest/XCTest.h>
#import "objc/util/TINKStrings.h"
-#import "proto/Tink.pbobjc.h"
#include "tink/util/test_util.h"
#include "proto/tink.pb.h"
diff --git a/objc/Tests/UnitTests/core/TINKJSONKeysetReaderTest.mm b/objc/Tests/UnitTests/core/TINKJSONKeysetReaderTest.mm
index bed6128..1cab383 100644
--- a/objc/Tests/UnitTests/core/TINKJSONKeysetReaderTest.mm
+++ b/objc/Tests/UnitTests/core/TINKJSONKeysetReaderTest.mm
@@ -21,7 +21,6 @@
#import <XCTest/XCTest.h>
#import "objc/util/TINKStrings.h"
-#import "proto/Tink.pbobjc.h"
#include "google/protobuf/util/json_util.h"
#include "tink/util/test_util.h"
diff --git a/objc/Tests/UnitTests/core/TINKKeysetHandleTest.mm b/objc/Tests/UnitTests/core/TINKKeysetHandleTest.mm
index 32c2abe..9809359 100644
--- a/objc/Tests/UnitTests/core/TINKKeysetHandleTest.mm
+++ b/objc/Tests/UnitTests/core/TINKKeysetHandleTest.mm
@@ -31,7 +31,6 @@
#import "objc/TINKSignatureKeyTemplate.h"
#import "objc/aead/TINKAeadInternal.h"
#import "objc/util/TINKStrings.h"
-#import "proto/Tink.pbobjc.h"
#include "tink/binary_keyset_reader.h"
#include "tink/util/status.h"
@@ -41,6 +40,7 @@
using ::crypto::tink::test::AddRawKey;
using ::crypto::tink::test::AddTinkKey;
+using ::google::crypto::tink::EncryptedKeyset;
using ::google::crypto::tink::KeyData;
using ::google::crypto::tink::Keyset;
using ::google::crypto::tink::KeyStatusType;
@@ -57,7 +57,7 @@
static NSString *const kBadKeysetName = @"com.google.crypto.tink.badKeyset";
static NSString *const kNonExistentKeysetName = @"com.google.crypto.tink.noSuchKeyset";
-static TINKPBKeyset *gKeyset;
+static Keyset *gKeyset;
@interface TINKKeysetHandleTest : XCTestCase
@end
@@ -65,25 +65,22 @@
@implementation TINKKeysetHandleTest
+ (void)setUp {
- google::crypto::tink::Keyset ccKeyset;
+ gKeyset = new Keyset();
google::crypto::tink::Keyset::Key ccKey;
crypto::tink::test::AddTinkKey("some key type", 42, ccKey,
google::crypto::tink::KeyStatusType::ENABLED,
- google::crypto::tink::KeyData::SYMMETRIC, &ccKeyset);
+ google::crypto::tink::KeyData::SYMMETRIC, gKeyset);
crypto::tink::test::AddRawKey("some other key type", 711, ccKey,
google::crypto::tink::KeyStatusType::ENABLED,
- google::crypto::tink::KeyData::SYMMETRIC, &ccKeyset);
- ccKeyset.set_primary_key_id(42);
+ google::crypto::tink::KeyData::SYMMETRIC, gKeyset);
+ gKeyset->set_primary_key_id(42);
- std::string serializedKeyset = ccKeyset.SerializeAsString();
+ std::string serializedKeyset = gKeyset->SerializeAsString();
gGoodSerializedKeyset = TINKStringToNSData(serializedKeyset);
NSError *error = nil;
- gKeyset = [TINKPBKeyset
- parseFromData:[NSData dataWithBytes:serializedKeyset.data() length:serializedKeyset.length()]
- error:&error];
- XCTAssertNotNil(gKeyset);
+ XCTAssertTrue(gKeyset != nil);
XCTAssertNil(error);
gBadSerializedKeyset = TINKStringToNSData("some weird string");
@@ -130,15 +127,21 @@
std::unique_ptr<crypto::tink::Aead>(new crypto::tink::test::DummyAead("dummy aead 42"));
TINKAeadInternal *aead = [[TINKAeadInternal alloc] initWithCCAead:std::move(ccAead)];
- NSData *keysetCiphertext = [aead encrypt:gKeyset.data withAdditionalData:[NSData data] error:nil];
+ std::string serializedKeyset = gKeyset->SerializeAsString();
+ NSData *serializedKeysetData = [[NSData alloc] initWithBytes:serializedKeyset.data()
+ length:serializedKeyset.size()];
+ NSData *keysetCiphertext = [aead encrypt:serializedKeysetData
+ withAdditionalData:[NSData data]
+ error:nil];
XCTAssertNotNil(keysetCiphertext);
- TINKPBEncryptedKeyset *encryptedKeyset = [[TINKPBEncryptedKeyset alloc] init];
- encryptedKeyset.encryptedKeyset = keysetCiphertext;
+ EncryptedKeyset encryptedKeyset;
+ encryptedKeyset.set_encrypted_keyset(NSDataToTINKString(keysetCiphertext));
- TINKBinaryKeysetReader *reader =
- [[TINKBinaryKeysetReader alloc] initWithSerializedKeyset:encryptedKeyset.data error:nil];
+ TINKBinaryKeysetReader *reader = [[TINKBinaryKeysetReader alloc]
+ initWithSerializedKeyset:TINKStringToNSData(encryptedKeyset.SerializeAsString())
+ error:nil];
TINKKeysetHandle *handle =
[[TINKKeysetHandle alloc] initWithKeysetReader:reader andKey:aead error:nil];
@@ -146,8 +149,8 @@
std::string output;
crypto::tink::TestKeysetHandle::GetKeyset(*handle.ccKeysetHandle).SerializeToString(&output);
- XCTAssertTrue(
- [gKeyset.data isEqualToData:[NSData dataWithBytes:output.data() length:output.size()]]);
+ XCTAssertTrue([serializedKeysetData isEqualToData:[NSData dataWithBytes:output.data()
+ length:output.size()]]);
}
- (void)testWrongAead_Binary {
@@ -155,13 +158,20 @@
std::unique_ptr<crypto::tink::Aead>(new crypto::tink::test::DummyAead("dummy aead 42"));
TINKAeadInternal *aead = [[TINKAeadInternal alloc] initWithCCAead:std::move(ccAead)];
- NSData *keysetCiphertext = [aead encrypt:gKeyset.data withAdditionalData:[NSData data] error:nil];
+ std::string serializedKeyset = gKeyset->SerializeAsString();
+ NSData *serializedKeysetData = [[NSData alloc] initWithBytes:serializedKeyset.data()
+ length:serializedKeyset.size()];
- TINKPBEncryptedKeyset *encryptedKeyset = [[TINKPBEncryptedKeyset alloc] init];
- encryptedKeyset.encryptedKeyset = keysetCiphertext;
+ NSData *keysetCiphertext = [aead encrypt:serializedKeysetData
+ withAdditionalData:[NSData data]
+ error:nil];
- TINKBinaryKeysetReader *reader =
- [[TINKBinaryKeysetReader alloc] initWithSerializedKeyset:encryptedKeyset.data error:nil];
+ EncryptedKeyset encryptedKeyset;
+ encryptedKeyset.set_encrypted_keyset(NSDataToTINKString(keysetCiphertext));
+
+ TINKBinaryKeysetReader *reader = [[TINKBinaryKeysetReader alloc]
+ initWithSerializedKeyset:TINKStringToNSData(encryptedKeyset.SerializeAsString())
+ error:nil];
auto ccWrongAead =
std::unique_ptr<crypto::tink::Aead>(new crypto::tink::test::DummyAead("wrong aead"));
@@ -197,13 +207,14 @@
auto ccAead =
std::unique_ptr<crypto::tink::Aead>(new crypto::tink::test::DummyAead("dummy aead 42"));
TINKAeadInternal *aead = [[TINKAeadInternal alloc] initWithCCAead:std::move(ccAead)];
- NSString *keysetCiphertext = @"totally wrong ciphertext";
+ NSData *keysetCiphertext = [@"totally wrong ciphertext" dataUsingEncoding:NSUTF8StringEncoding];
- TINKPBEncryptedKeyset *encryptedKeyset = [[TINKPBEncryptedKeyset alloc] init];
- encryptedKeyset.encryptedKeyset = [keysetCiphertext dataUsingEncoding:NSUTF8StringEncoding];
+ EncryptedKeyset encryptedKeyset;
+ encryptedKeyset.set_encrypted_keyset(NSDataToTINKString(keysetCiphertext));
- TINKBinaryKeysetReader *reader =
- [[TINKBinaryKeysetReader alloc] initWithSerializedKeyset:encryptedKeyset.data error:nil];
+ TINKBinaryKeysetReader *reader = [[TINKBinaryKeysetReader alloc]
+ initWithSerializedKeyset:TINKStringToNSData(encryptedKeyset.SerializeAsString())
+ error:nil];
NSError *error = nil;
TINKKeysetHandle *handle =
[[TINKKeysetHandle alloc] initWithKeysetReader:reader andKey:aead error:&error];
@@ -231,15 +242,21 @@
std::unique_ptr<crypto::tink::Aead>(new crypto::tink::test::DummyAead("dummy aead 42"));
TINKAeadInternal *aead = [[TINKAeadInternal alloc] initWithCCAead:std::move(ccAead)];
- NSData *keysetCiphertext = [aead encrypt:gKeyset.data withAdditionalData:[NSData data] error:nil];
+ std::string serializedKeyset = gKeyset->SerializeAsString();
+ NSData *serializedKeysetData = [[NSData alloc] initWithBytes:serializedKeyset.data()
+ length:serializedKeyset.size()];
+ NSData *keysetCiphertext = [aead encrypt:serializedKeysetData
+ withAdditionalData:[NSData data]
+ error:nil];
XCTAssertNotNil(keysetCiphertext);
- TINKPBEncryptedKeyset *encryptedKeyset = [[TINKPBEncryptedKeyset alloc] init];
- encryptedKeyset.encryptedKeyset = keysetCiphertext;
+ EncryptedKeyset encryptedKeyset;
+ encryptedKeyset.set_encrypted_keyset(NSDataToTINKString(keysetCiphertext));
- TINKBinaryKeysetReader *reader =
- [[TINKBinaryKeysetReader alloc] initWithSerializedKeyset:encryptedKeyset.data error:nil];
+ TINKBinaryKeysetReader *reader = [[TINKBinaryKeysetReader alloc]
+ initWithSerializedKeyset:TINKStringToNSData(encryptedKeyset.SerializeAsString())
+ error:nil];
TINKKeysetHandle *handle =
[[TINKKeysetHandle alloc] initWithKeysetReader:reader andKey:aead error:nil];
diff --git a/objc/Tests/UnitTests/daead/TINKDeterministicAeadKeyTemplateTest.mm b/objc/Tests/UnitTests/daead/TINKDeterministicAeadKeyTemplateTest.mm
index 07592b4..098252b 100644
--- a/objc/Tests/UnitTests/daead/TINKDeterministicAeadKeyTemplateTest.mm
+++ b/objc/Tests/UnitTests/daead/TINKDeterministicAeadKeyTemplateTest.mm
@@ -22,10 +22,8 @@
#import "objc/TINKKeyTemplate.h"
#import "objc/core/TINKKeyTemplate_Internal.h"
-#import "objc/util/TINKProtoHelpers.h"
-#import "proto/AesSiv.pbobjc.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
+#include "proto/common.pb.h"
+#include "proto/tink.pb.h"
@interface TINKDeterministicAeadKeyTemplatesTest : XCTestCase
@end
@@ -33,7 +31,7 @@
@implementation TINKDeterministicAeadKeyTemplatesTest
- (void)testAesSivKeyTemplates {
- static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.AesSivKey";
+ static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.AesSivKey";
NSError *error = nil;
// AES-256 SIV
@@ -42,19 +40,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBAesSivKeyFormat *keyFormat = [TINKPBAesSivKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
- XCTAssertTrue(64 == keyFormat.keySize);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
@end
diff --git a/objc/Tests/UnitTests/hybrid/TINKHybridDecryptFactoryTest.mm b/objc/Tests/UnitTests/hybrid/TINKHybridDecryptFactoryTest.mm
index 0caa583..643d6c2 100644
--- a/objc/Tests/UnitTests/hybrid/TINKHybridDecryptFactoryTest.mm
+++ b/objc/Tests/UnitTests/hybrid/TINKHybridDecryptFactoryTest.mm
@@ -21,9 +21,9 @@
#include "tink/crypto_format.h"
#include "tink/util/status.h"
#include "tink/util/test_keyset_handle.h"
-
-#import "proto/EciesAeadHkdf.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
+#include "tink/util/test_util.h"
+#include "proto/ecies_aead_hkdf.pb.h"
+#include "proto/tink.pb.h"
#import "objc/TINKConfig.h"
#import "objc/TINKHybridConfig.h"
@@ -34,39 +34,38 @@
#import "objc/TINKKeysetHandle.h"
#import "objc/core/TINKKeysetHandle_Internal.h"
#import "objc/util/TINKStrings.h"
-#import "objc/util/TINKTestHelpers.h"
-using crypto::tink::TestKeysetHandle;
+using ::crypto::tink::TestKeysetHandle;
+using ::crypto::tink::test::AddTinkKey;
+using ::crypto::tink::test::AddRawKey;
+using ::crypto::tink::test::AddLegacyKey;
+using ::google::crypto::tink::EciesAeadHkdfPrivateKey;
+using ::google::crypto::tink::EcPointFormat;
+using ::google::crypto::tink::EllipticCurveType;
+using ::google::crypto::tink::HashType;
+using ::google::crypto::tink::KeyData;
+using ::google::crypto::tink::Keyset;
+using ::google::crypto::tink::KeyStatusType;
@interface TINKHybridDecryptFactoryTest : XCTestCase
@end
-static TINKPBEciesAeadHkdfPrivateKey *getNewEciesPrivateKey() {
- return TINKGetEciesAesGcmHkdfTestKey(TINKPBEllipticCurveType_NistP256,
- TINKPBEcPointFormat_Uncompressed, TINKPBHashType_Sha256, 32);
+static EciesAeadHkdfPrivateKey getNewEciesPrivateKey() {
+ return crypto::tink::test::GetEciesAesGcmHkdfTestKey(
+ EllipticCurveType::NIST_P256, EcPointFormat::UNCOMPRESSED, HashType::SHA256, 32);
}
@implementation TINKHybridDecryptFactoryTest
-- (void)testEncryptWith:(TINKPBKeyset *)publicKeyset andDecryptWith:(TINKPBKeyset *)privateKeyset {
- NSError *error = nil;
- std::string serializedKeyset = TINKPBSerializeToString(privateKeyset, &error);
- XCTAssertNil(error);
- google::crypto::tink::Keyset ccPrivateKeyset;
- XCTAssertTrue(ccPrivateKeyset.ParseFromString(serializedKeyset));
+- (void)testEncryptWith:(Keyset *)publicKeyset andDecryptWith:(Keyset *)privateKeyset {
TINKKeysetHandle *privateKeysetHandle = [[TINKKeysetHandle alloc]
- initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(ccPrivateKeyset)];
+ initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(*privateKeyset)];
- error = nil;
- serializedKeyset = TINKPBSerializeToString(publicKeyset, &error);
- XCTAssertNil(error);
- google::crypto::tink::Keyset ccPublicKeyset;
- XCTAssertTrue(ccPublicKeyset.ParseFromString(serializedKeyset));
TINKKeysetHandle *publicKeysetHandle = [[TINKKeysetHandle alloc]
- initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(ccPublicKeyset)];
+ initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(*publicKeyset)];
// Get a HybridDecrypt primitive.
- error = nil;
+ NSError *error = nil;
id<TINKHybridDecrypt> hybridDecrypt =
[TINKHybridDecryptFactory primitiveWithKeysetHandle:privateKeysetHandle error:&error];
XCTAssertNotNil(hybridDecrypt);
@@ -126,56 +125,39 @@
uint32_t keyId1 = 1;
uint32_t keyId2 = 2;
uint32_t keyId3 = 3;
- TINKPBEciesAeadHkdfPrivateKey *eciesKey1 = getNewEciesPrivateKey();
- TINKPBEciesAeadHkdfPrivateKey *eciesKey2 = getNewEciesPrivateKey();
- TINKPBEciesAeadHkdfPrivateKey *eciesKey3 = getNewEciesPrivateKey();
+ EciesAeadHkdfPrivateKey eciesKey1 = getNewEciesPrivateKey();
+ EciesAeadHkdfPrivateKey eciesKey2 = getNewEciesPrivateKey();
+ EciesAeadHkdfPrivateKey eciesKey3 = getNewEciesPrivateKey();
- NSString *privateKeyType = @"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey";
- TINKPBKeyset_Key *tinkPrivateKey =
- TINKCreateKey(privateKeyType, keyId1, eciesKey1, TINKPBOutputPrefixType_Tink,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPrivate);
- TINKPBKeyset_Key *rawPrivateKey =
- TINKCreateKey(privateKeyType, keyId2, eciesKey2, TINKPBOutputPrefixType_Raw,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPrivate);
- TINKPBKeyset_Key *legacyPrivateKey =
- TINKCreateKey(privateKeyType, keyId3, eciesKey3, TINKPBOutputPrefixType_Legacy,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPrivate);
+ std::string privateKeyType = "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey";
+ Keyset privateKeyset;
+ AddTinkKey(privateKeyType, keyId1, eciesKey1, KeyStatusType::ENABLED, KeyData::ASYMMETRIC_PRIVATE,
+ &privateKeyset);
+ AddRawKey(privateKeyType, keyId2, eciesKey2, KeyStatusType::ENABLED, KeyData::ASYMMETRIC_PRIVATE,
+ &privateKeyset);
+ AddLegacyKey(privateKeyType, keyId3, eciesKey3, KeyStatusType::ENABLED,
+ KeyData::ASYMMETRIC_PRIVATE, &privateKeyset);
- NSString *publicKeyType = @"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey";
- TINKPBKeyset_Key *tinkPublicKey =
- TINKCreateKey(publicKeyType, keyId1, eciesKey1.publicKey, TINKPBOutputPrefixType_Tink,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPublic);
- TINKPBKeyset_Key *rawPublicKey =
- TINKCreateKey(publicKeyType, keyId2, eciesKey2.publicKey, TINKPBOutputPrefixType_Raw,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPublic);
- TINKPBKeyset_Key *legacyPublicKey =
- TINKCreateKey(publicKeyType, keyId3, eciesKey3.publicKey, TINKPBOutputPrefixType_Legacy,
- TINKPBKeyStatusType_Enabled, TINKPBKeyData_KeyMaterialType_AsymmetricPublic);
+ std::string publicKeyType = "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey";
+ Keyset publicKeyset;
+ AddTinkKey(publicKeyType, keyId1, eciesKey1.public_key(), KeyStatusType::ENABLED,
+ KeyData::ASYMMETRIC_PUBLIC, &publicKeyset);
+ AddRawKey(publicKeyType, keyId2, eciesKey2.public_key(), KeyStatusType::ENABLED,
+ KeyData::ASYMMETRIC_PUBLIC, &publicKeyset);
+ AddLegacyKey(publicKeyType, keyId3, eciesKey3.public_key(), KeyStatusType::ENABLED,
+ KeyData::ASYMMETRIC_PUBLIC, &publicKeyset);
- // Encrypt with tink and decrypt with tink.
- TINKPBKeyset *privateKeyset = TINKCreateKeyset(tinkPrivateKey, rawPrivateKey, legacyPrivateKey);
- TINKPBKeyset *publicKeyset = TINKCreateKeyset(tinkPublicKey, rawPublicKey, legacyPublicKey);
- [self testEncryptWith:publicKeyset andDecryptWith:privateKeyset];
+ privateKeyset.set_primary_key_id(keyId1);
+ publicKeyset.set_primary_key_id(keyId3);
+ [self testEncryptWith:&publicKeyset andDecryptWith:&privateKeyset];
- // Encrypt with raw and decrypt with raw.
- privateKeyset = TINKCreateKeyset(rawPrivateKey, tinkPrivateKey, legacyPrivateKey);
- publicKeyset = TINKCreateKeyset(rawPublicKey, tinkPublicKey, legacyPublicKey);
- [self testEncryptWith:publicKeyset andDecryptWith:privateKeyset];
+ privateKeyset.set_primary_key_id(keyId2);
+ publicKeyset.set_primary_key_id(keyId3);
+ [self testEncryptWith:&publicKeyset andDecryptWith:&privateKeyset];
- // Encrypt with legacy and decrypt with legacy
- privateKeyset = TINKCreateKeyset(legacyPrivateKey, tinkPrivateKey, rawPrivateKey);
- publicKeyset = TINKCreateKeyset(legacyPublicKey, tinkPublicKey, rawPublicKey);
- [self testEncryptWith:publicKeyset andDecryptWith:privateKeyset];
-
- // Encrypt with tink as primary, decrypt with raw as primary.
- publicKeyset = TINKCreateKeyset(tinkPublicKey, legacyPublicKey, rawPublicKey);
- privateKeyset = TINKCreateKeyset(rawPrivateKey, tinkPrivateKey, legacyPrivateKey);
- [self testEncryptWith:publicKeyset andDecryptWith:privateKeyset];
-
- // Encrypt with raw as primary, decrypt with tink as primary.
- publicKeyset = TINKCreateKeyset(rawPublicKey, tinkPublicKey, legacyPublicKey);
- privateKeyset = TINKCreateKeyset(tinkPrivateKey, rawPrivateKey, legacyPrivateKey);
- [self testEncryptWith:publicKeyset andDecryptWith:privateKeyset];
+ privateKeyset.set_primary_key_id(keyId3);
+ publicKeyset.set_primary_key_id(keyId1);
+ [self testEncryptWith:&publicKeyset andDecryptWith:&privateKeyset];
}
@end
diff --git a/objc/Tests/UnitTests/hybrid/TINKHybridEncryptFactoryTest.mm b/objc/Tests/UnitTests/hybrid/TINKHybridEncryptFactoryTest.mm
index 2c58b5d..e9a193f 100644
--- a/objc/Tests/UnitTests/hybrid/TINKHybridEncryptFactoryTest.mm
+++ b/objc/Tests/UnitTests/hybrid/TINKHybridEncryptFactoryTest.mm
@@ -20,12 +20,10 @@
#include "tink/util/status.h"
#include "tink/util/test_keyset_handle.h"
+#include "tink/util/test_util.h"
+#include "proto/ecies_aead_hkdf.pb.h"
#include "proto/tink.pb.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/EciesAeadHkdf.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
-
#import "objc/TINKConfig.h"
#import "objc/TINKHybridConfig.h"
#import "objc/TINKHybridEncrypt.h"
@@ -33,18 +31,25 @@
#import "objc/TINKKeysetHandle.h"
#import "objc/core/TINKKeysetHandle_Internal.h"
#import "objc/util/TINKStrings.h"
-#import "objc/util/TINKTestHelpers.h"
-using crypto::tink::TestKeysetHandle;
+using ::crypto::tink::TestKeysetHandle;
+using ::crypto::tink::test::AddTinkKey;
+using ::crypto::tink::test::AddRawKey;
+using ::crypto::tink::test::AddLegacyKey;
+using ::google::crypto::tink::EciesAeadHkdfPublicKey;
+using ::google::crypto::tink::EcPointFormat;
+using ::google::crypto::tink::EllipticCurveType;
+using ::google::crypto::tink::HashType;
+using ::google::crypto::tink::KeyData;
+using ::google::crypto::tink::Keyset;
+using ::google::crypto::tink::KeyStatusType;
@interface TINKHybridEncryptFactoryTest : XCTestCase
@end
-static TINKPBEciesAeadHkdfPublicKey *getNewEciesPublicKey() {
- TINKPBEciesAeadHkdfPrivateKey *eciesKey =
- TINKGetEciesAesGcmHkdfTestKey(TINKPBEllipticCurveType_NistP256,
- TINKPBEcPointFormat_Uncompressed, TINKPBHashType_Sha256, 32);
- return eciesKey.publicKey;
+static EciesAeadHkdfPublicKey getNewEciesPublicKey() {
+ return crypto::tink::test::GetEciesAesGcmHkdfTestKey(
+ EllipticCurveType::NIST_P256, EcPointFormat::UNCOMPRESSED, HashType::SHA256, 32).public_key();
}
@implementation TINKHybridEncryptFactoryTest
@@ -68,50 +73,35 @@
- (void)testPrimitiveWithKeyset {
// Prepare a Keyset.
- TINKPBKeyset *keyset = [[TINKPBKeyset alloc] init];
- NSString *keyType = @"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey";
+ Keyset publicKeyset;
+ std::string publicKeyType = "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey";
- uint32_t key_id_1 = 1234543;
- TINKAddTinkKey(keyType, key_id_1, getNewEciesPublicKey(), TINKPBKeyStatusType_Enabled,
- TINKPBKeyData_KeyMaterialType_AsymmetricPublic, keyset);
+ uint32_t keyId1 = 1234543;
+ uint32_t keyId2 = 726329;
+ uint32_t keyId3 = 7213743;
+ EciesAeadHkdfPublicKey eciesKey1 = getNewEciesPublicKey();
+ EciesAeadHkdfPublicKey eciesKey2 = getNewEciesPublicKey();
+ EciesAeadHkdfPublicKey eciesKey3 = getNewEciesPublicKey();
- uint32_t key_id_2 = 726329;
- TINKAddRawKey(keyType, key_id_2, getNewEciesPublicKey(), TINKPBKeyStatusType_Enabled,
- TINKPBKeyData_KeyMaterialType_AsymmetricPublic, keyset);
+ AddTinkKey(publicKeyType, keyId1, eciesKey1, KeyStatusType::ENABLED, KeyData::ASYMMETRIC_PUBLIC,
+ &publicKeyset);
+ AddRawKey(publicKeyType, keyId2, eciesKey2, KeyStatusType::ENABLED, KeyData::ASYMMETRIC_PUBLIC,
+ &publicKeyset);
+ AddLegacyKey(publicKeyType, keyId3, eciesKey3, KeyStatusType::ENABLED, KeyData::ASYMMETRIC_PUBLIC,
+ &publicKeyset);
- uint32_t key_id_3 = 7213743;
- TINKAddTinkKey(keyType, key_id_3, getNewEciesPublicKey(), TINKPBKeyStatusType_Enabled,
- TINKPBKeyData_KeyMaterialType_AsymmetricPublic, keyset);
- XCTAssertEqual(keyset.keyArray_Count, 3);
-
- keyset.primaryKeyId = key_id_3;
-
- // Initialize the registry.
- NSError *error = nil;
- TINKHybridConfig *hybridConfig = [[TINKHybridConfig alloc] initWithError:&error];
- XCTAssertNotNil(hybridConfig);
- XCTAssertNil(error);
-
- XCTAssertTrue([TINKConfig registerConfig:hybridConfig error:&error]);
- XCTAssertNil(error);
-
- std::string serializedKeyset = TINKPBSerializeToString(keyset, &error);
- XCTAssertNil(error);
-
- google::crypto::tink::Keyset ccKeyset;
- XCTAssertTrue(ccKeyset.ParseFromString(serializedKeyset));
-
+ publicKeyset.set_primary_key_id(keyId3);
// Create a KeysetHandle and use it with the factory.
TINKKeysetHandle *keysetHandle = [[TINKKeysetHandle alloc]
- initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(ccKeyset)];
+ initWithCCKeysetHandle:TestKeysetHandle::GetKeysetHandle(publicKeyset)];
XCTAssertNotNil(keysetHandle);
// Get a HybridEncrypt primitive.
- error = nil;
+ NSError *error = nil;
id<TINKHybridEncrypt> primitive =
[TINKHybridEncryptFactory primitiveWithKeysetHandle:keysetHandle error:&error];
- XCTAssertNotNil(primitive);
XCTAssertNil(error);
+ XCTAssertNotNil(primitive);
// Test the resulting HybridEncrypt-instance.
NSData *plaintext = [@"some plaintext" dataUsingEncoding:NSUTF8StringEncoding];
diff --git a/objc/Tests/UnitTests/hybrid/TINKHybridKeyTemplateTest.mm b/objc/Tests/UnitTests/hybrid/TINKHybridKeyTemplateTest.mm
index 1c6e799..27f9038 100644
--- a/objc/Tests/UnitTests/hybrid/TINKHybridKeyTemplateTest.mm
+++ b/objc/Tests/UnitTests/hybrid/TINKHybridKeyTemplateTest.mm
@@ -23,17 +23,16 @@
#import "objc/TINKAeadKeyTemplate.h"
#import "objc/TINKKeyTemplate.h"
#import "objc/core/TINKKeyTemplate_Internal.h"
-#import "objc/util/TINKProtoHelpers.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/EciesAeadHkdf.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
+#include "proto/common.pb.h"
+#include "proto/tink.pb.h"
#include "tink/util/status.h"
@interface TINKHybridKeyTemplateTest : XCTestCase
@end
-static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey";
+static std::string const kTypeURL =
+ "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey";
@implementation TINKHybridKeyTemplateTest
@@ -59,46 +58,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBEciesAeadHkdfKeyFormat *keyFormat =
- [TINKPBEciesAeadHkdfKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- // EC Point Format
- XCTAssertEqual(TINKPBEcPointFormat_Uncompressed, keyFormat.params.ecPointFormat);
-
- // Verify DEM params.
- XCTAssertTrue(keyFormat.params.hasDemParams);
- TINKPBEciesAeadDemParams *demParams = keyFormat.params.demParams;
- error = nil;
- TINKAeadKeyTemplate *expectedDemTpl =
- [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes128Gcm error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(expectedDemTpl);
-
- error = nil;
- TINKPBKeyTemplate *expectedDem = TINKKeyTemplateToObjc(expectedDemTpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(expectedDem);
-
- XCTAssertTrue(demParams.hasAeadDem);
- XCTAssertEqual(expectedDem.outputPrefixType, demParams.aeadDem.outputPrefixType);
- XCTAssertTrue([expectedDem.typeURL isEqualToString:demParams.aeadDem.typeURL]);
- XCTAssertTrue([expectedDem.value isEqualToData:demParams.aeadDem.value]);
-
- // Verify KEM params.
- XCTAssertTrue(keyFormat.params.hasKemParams);
- TINKPBEciesHkdfKemParams *kemParams = keyFormat.params.kemParams;
- XCTAssertEqual(TINKPBEllipticCurveType_NistP256, kemParams.curveType);
- XCTAssertEqual(TINKPBHashType_Sha256, kemParams.hkdfHashType);
- XCTAssertTrue(kemParams.hkdfSalt.length == 0);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEciesP256HkdfHmacSha256Aes128CtrHmacSha256 {
@@ -110,47 +72,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBEciesAeadHkdfKeyFormat *keyFormat =
- [TINKPBEciesAeadHkdfKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- // EC Point Format
- XCTAssertEqual(TINKPBEcPointFormat_Uncompressed, keyFormat.params.ecPointFormat);
-
- // Verify DEM params.
- XCTAssertTrue(keyFormat.params.hasDemParams);
- TINKPBEciesAeadDemParams *demParams = keyFormat.params.demParams;
-
- error = nil;
- TINKAeadKeyTemplate *tpl =
- [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes128CtrHmacSha256 error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(tpl);
-
- error = nil;
- TINKPBKeyTemplate *expectedDem = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(expectedDem);
-
- XCTAssertTrue(demParams.hasAeadDem);
- XCTAssertEqual(expectedDem.outputPrefixType, demParams.aeadDem.outputPrefixType);
- XCTAssertTrue([expectedDem.typeURL isEqualToString:demParams.aeadDem.typeURL]);
- XCTAssertTrue([expectedDem.value isEqualToData:demParams.aeadDem.value]);
-
- // Verify KEM params.
- XCTAssertTrue(keyFormat.params.hasKemParams);
- TINKPBEciesHkdfKemParams *kemParams = keyFormat.params.kemParams;
- XCTAssertEqual(TINKPBEllipticCurveType_NistP256, kemParams.curveType);
- XCTAssertEqual(TINKPBHashType_Sha256, kemParams.hkdfHashType);
- XCTAssertTrue(kemParams.hkdfSalt.length == 0);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
@end
diff --git a/objc/Tests/UnitTests/mac/TINKMacKeyTemplateTest.mm b/objc/Tests/UnitTests/mac/TINKMacKeyTemplateTest.mm
index fda2cb0..f8760b0 100644
--- a/objc/Tests/UnitTests/mac/TINKMacKeyTemplateTest.mm
+++ b/objc/Tests/UnitTests/mac/TINKMacKeyTemplateTest.mm
@@ -22,19 +22,16 @@
#import "objc/TINKKeyTemplate.h"
#import "objc/core/TINKKeyTemplate_Internal.h"
-#import "objc/util/TINKProtoHelpers.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/AesCmac.pbobjc.h"
-#import "proto/Hmac.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
+#include "proto/common.pb.h"
+#include "proto/tink.pb.h"
#include "tink/util/status.h"
@interface TINKMacKeyTemplateTest : XCTestCase
@end
-static NSString *const kHmacKeyTypeURL = @"type.googleapis.com/google.crypto.tink.HmacKey";
-static NSString *const kAesCmacKeyTypeURL = @"type.googleapis.com/google.crypto.tink.AesCmacKey";
+static std::string const kHmacKeyTypeURL = "type.googleapis.com/google.crypto.tink.HmacKey";
+static std::string const kAesCmacKeyTypeURL = "type.googleapis.com/google.crypto.tink.AesCmacKey";
@implementation TINKMacKeyTemplateTest
@@ -59,21 +56,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kHmacKeyTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBHmacKeyFormat *keyFormat =
- [TINKPBHmacKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.keySize, 32);
- XCTAssertEqual(keyFormat.params.tagSize, 16);
- XCTAssertEqual(keyFormat.params.hash_p, TINKPBHashType_Sha256);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kHmacKeyTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testHmac256BittagSha256 {
@@ -84,21 +69,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kHmacKeyTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBHmacKeyFormat *keyFormat =
- [TINKPBHmacKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.keySize, 32);
- XCTAssertEqual(keyFormat.params.tagSize, 32);
- XCTAssertEqual(keyFormat.params.hash_p, TINKPBHashType_Sha256);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kHmacKeyTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testHmac256BittagSha512 {
@@ -109,21 +82,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kHmacKeyTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBHmacKeyFormat *keyFormat = [TINKPBHmacKeyFormat parseFromData:objcKeyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.keySize, 64);
- XCTAssertEqual(keyFormat.params.tagSize, 32);
- XCTAssertEqual(keyFormat.params.hash_p, TINKPBHashType_Sha512);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kHmacKeyTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testHmac512BittagSha512 {
@@ -134,21 +95,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kHmacKeyTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBHmacKeyFormat *keyFormat =
- [TINKPBHmacKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.keySize, 64);
- XCTAssertEqual(keyFormat.params.tagSize, 64);
- XCTAssertEqual(keyFormat.params.hash_p, TINKPBHashType_Sha512);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kHmacKeyTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testAesCmac {
@@ -159,20 +108,9 @@
XCTAssertNil(error);
XCTAssertNotNil(keyTemplate);
- TINKPBKeyTemplate *objcKeyTemplate = TINKKeyTemplateToObjc(keyTemplate.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(objcKeyTemplate);
-
- XCTAssertTrue([kAesCmacKeyTypeURL isEqualToString:objcKeyTemplate.typeURL]);
- XCTAssertEqual(objcKeyTemplate.outputPrefixType, TINKPBOutputPrefixType_Tink);
- error = nil;
- TINKPBAesCmacKeyFormat *keyFormat =
- [TINKPBAesCmacKeyFormat parseFromData:objcKeyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.keySize, 32);
- XCTAssertEqual(keyFormat.params.tagSize, 16);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->type_url() == kAesCmacKeyTypeURL);
+ XCTAssertTrue(keyTemplate.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
@end
diff --git a/objc/Tests/UnitTests/signature/TINKSignatureKeyTemplateTest.mm b/objc/Tests/UnitTests/signature/TINKSignatureKeyTemplateTest.mm
index 4716aa1..6b534dd 100644
--- a/objc/Tests/UnitTests/signature/TINKSignatureKeyTemplateTest.mm
+++ b/objc/Tests/UnitTests/signature/TINKSignatureKeyTemplateTest.mm
@@ -22,26 +22,21 @@
#import "objc/TINKKeyTemplate.h"
#import "objc/core/TINKKeyTemplate_Internal.h"
-#import "objc/util/TINKProtoHelpers.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/Ecdsa.pbobjc.h"
-#import "proto/Empty.pbobjc.h"
-#import "proto/RsaSsaPkcs1.pbobjc.h"
-#import "proto/RsaSsaPss.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
+#include "proto/common.pb.h"
+#include "proto/tink.pb.h"
#include "tink/util/status.h"
@interface TINKSignatureKeyTemplatesTest : XCTestCase
@end
-static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.EcdsaPrivateKey";
-static NSString *const kTypeURLRsaPss =
- @"type.googleapis.com/google.crypto.tink.RsaSsaPssPrivateKey";
-static NSString *const kTypeURLRsaPkcs1 =
- @"type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey";
-static NSString *const kTypeURLEd25519 =
- @"type.googleapis.com/google.crypto.tink.Ed25519PrivateKey";
+static std::string const kTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey";
+static std::string const kTypeURLRsaPss =
+ "type.googleapis.com/google.crypto.tink.RsaSsaPssPrivateKey";
+static std::string const kTypeURLRsaPkcs1 =
+ "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey";
+static std::string const kTypeURLEd25519 =
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey";
@implementation TINKSignatureKeyTemplatesTest
@@ -52,23 +47,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat =
- [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha256);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP256);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_Der);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEcdsaP256KeyTemplateWithIeeeEncoding {
@@ -78,23 +59,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat = [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha256);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP256);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_IeeeP1363);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEcdsaP384KeyTemplateWithDerEncoding {
@@ -104,23 +71,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat =
- [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP384);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_Der);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEcdsaP384KeyTemplateWithIeeeEncoding {
@@ -130,23 +83,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat = [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP384);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_IeeeP1363);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEcdsaP521KeyTemplateWithDerEncoding {
@@ -156,23 +95,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat =
- [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP521);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_Der);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEcdsaP521KeyTemplateWithIeeeEncoding {
@@ -182,23 +107,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURL isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEcdsaKeyFormat *keyFormat = [TINKPBEcdsaKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.curve, TINKPBEllipticCurveType_NistP521);
- XCTAssertEqual(keyFormat.params.encoding, TINKPBEcdsaSignatureEncoding_IeeeP1363);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURL);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testInvalidKeyTemplate {
@@ -221,21 +132,10 @@
XCTAssertNotNil(tpl);
error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
- XCTAssertTrue([kTypeURLRsaPkcs1 isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBRsaSsaPkcs1KeyFormat *keyFormat =
- [TINKPBRsaSsaPkcs1KeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha256);
- XCTAssertEqual(keyFormat.modulusSizeInBits, 3072);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURLRsaPkcs1);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testRsaSsaPkcs14096Sha512F4KeyTemplate {
@@ -246,22 +146,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURLRsaPkcs1 isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBRsaSsaPkcs1KeyFormat *keyFormat =
- [TINKPBRsaSsaPkcs1KeyFormat parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.hashType, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.modulusSizeInBits, 4096);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURLRsaPkcs1);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testRsaSsaPss3072Sha256F4KeyTemplate {
@@ -272,24 +159,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURLRsaPss isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBRsaSsaPssKeyFormat *keyFormat = [TINKPBRsaSsaPssKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.sigHash, TINKPBHashType_Sha256);
- XCTAssertEqual(keyFormat.params.mgf1Hash, TINKPBHashType_Sha256);
- XCTAssertEqual(keyFormat.params.saltLength, 32);
- XCTAssertEqual(keyFormat.modulusSizeInBits, 3072);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURLRsaPss);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testRsaSsaPss4096Sha512F4KeyTemplate {
@@ -300,24 +172,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURLRsaPss isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBRsaSsaPssKeyFormat *keyFormat = [TINKPBRsaSsaPssKeyFormat parseFromData:keyTemplate.value
- error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
-
- XCTAssertEqual(keyFormat.params.sigHash, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.mgf1Hash, TINKPBHashType_Sha512);
- XCTAssertEqual(keyFormat.params.saltLength, 64);
- XCTAssertEqual(keyFormat.modulusSizeInBits, 4096);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURLRsaPss);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
- (void)testEd25519KeyTemplate {
@@ -327,18 +184,9 @@
XCTAssertNil(error);
XCTAssertNotNil(tpl);
- error = nil;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(tpl.ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([kTypeURLEd25519 isEqualToString:keyTemplate.typeURL]);
- XCTAssertTrue(keyTemplate.outputPrefixType == TINKPBOutputPrefixType_Tink);
-
- error = nil;
- TINKPBEmpty *keyFormat = [TINKPBEmpty parseFromData:keyTemplate.value error:&error];
- XCTAssertNil(error);
- XCTAssertNotNil(keyFormat);
+ XCTAssertTrue(tpl.ccKeyTemplate->type_url() == kTypeURLEd25519);
+ XCTAssertTrue(tpl.ccKeyTemplate->output_prefix_type() ==
+ google::crypto::tink::OutputPrefixType::TINK);
}
@end
diff --git a/objc/Tests/UnitTests/util/TINKProtoHelpersTest.mm b/objc/Tests/UnitTests/util/TINKProtoHelpersTest.mm
deleted file mode 100644
index bfa8dad..0000000
--- a/objc/Tests/UnitTests/util/TINKProtoHelpersTest.mm
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- **************************************************************************
- */
-
-#import "objc/util/TINKProtoHelpers.h"
-
-#import <XCTest/XCTest.h>
-
-#import "proto/Tink.pbobjc.h"
-
-#include "proto/tink.pb.h"
-
-@interface TINKProtoHelpersTest : XCTestCase
-@end
-
-@implementation TINKProtoHelpersTest
-
-- (void)testConvertKeyTemplateToObjc {
- static NSString *const kTypeURL = @"type.googleapis.com/google.crypto.tink.AesGcmKey";
-
- NSError *error = nil;
-
- // Empty KeyTemplate.
- google::crypto::tink::KeyTemplate emptyKeyTemplate;
- TINKPBKeyTemplate *keyTemplate = TINKKeyTemplateToObjc(&emptyKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertEqual(keyTemplate.typeURL.length, 0);
- XCTAssertEqual(keyTemplate.value.length, 0);
- XCTAssertEqual(keyTemplate.outputPrefixType, TINKPBOutputPrefixType_UnknownPrefix);
-
- // Prepopulated KeyTemplate.
- google::crypto::tink::KeyTemplate ccKeyTemplate;
- ccKeyTemplate.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey");
- ccKeyTemplate.set_value("blah blah");
- ccKeyTemplate.set_output_prefix_type(google::crypto::tink::OutputPrefixType::TINK);
-
- keyTemplate = TINKKeyTemplateToObjc(&ccKeyTemplate, &error);
- XCTAssertNil(error);
- XCTAssertNotNil(keyTemplate);
-
- XCTAssertTrue([keyTemplate.typeURL isEqualToString:kTypeURL]);
- XCTAssertTrue(
- [keyTemplate.value isEqualToData:[@"blah blah" dataUsingEncoding:NSUTF8StringEncoding]]);
- XCTAssertEqual((NSInteger)ccKeyTemplate.output_prefix_type(),
- (NSInteger)keyTemplate.outputPrefixType);
-}
-
-@end
diff --git a/objc/util/TINKProtoHelpers.h b/objc/util/TINKProtoHelpers.h
deleted file mode 100644
index d8e4daa..0000000
--- a/objc/util/TINKProtoHelpers.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- **************************************************************************
- */
-
-#import <Foundation/Foundation.h>
-
-#include "proto/tink.pb.h"
-
-@class TINKPBKeyTemplate;
-
-/** Converts a C++ KeyTemplate protobuf to an Obj-C TINKPBKeyTemplate. */
-TINKPBKeyTemplate *TINKKeyTemplateToObjc(google::crypto::tink::KeyTemplate *ccKeyTemplate,
- NSError **error);
diff --git a/objc/util/TINKProtoHelpers.mm b/objc/util/TINKProtoHelpers.mm
deleted file mode 100644
index d56c493..0000000
--- a/objc/util/TINKProtoHelpers.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- **************************************************************************
- */
-
-#import "objc/util/TINKProtoHelpers.h"
-
-#import "objc/util/TINKErrors.h"
-#import "objc/util/TINKStrings.h"
-#import "proto/Tink.pbobjc.h"
-
-#include "tink/util/status.h"
-#include "proto/tink.pb.h"
-
-TINKPBKeyTemplate *TINKKeyTemplateToObjc(google::crypto::tink::KeyTemplate *ccKeyTemplate,
- NSError **error) {
- // Serialize it to std::string.
- std::string serializedKeyTemplate;
- if (!ccKeyTemplate->SerializeToString(&serializedKeyTemplate)) {
- if (error) {
- *error = TINKStatusToError(crypto::tink::util::Status(
- crypto::tink::util::error::INVALID_ARGUMENT, "Could not serialize C++ KeyTemplate."));
- }
- return nil;
- }
-
- // Deserialize it to an Obj-C TINKPBKeyTemplate.
- NSError *parseError = nil;
- TINKPBKeyTemplate *keyTemplate =
- [TINKPBKeyTemplate parseFromData:TINKStringToNSData(serializedKeyTemplate) error:&parseError];
- if (parseError) {
- if (error) {
- *error = parseError;
- }
- return nil;
- }
-
- return keyTemplate;
-}
diff --git a/objc/util/TINKStrings.h b/objc/util/TINKStrings.h
index 896c89b..6d4b098 100644
--- a/objc/util/TINKStrings.h
+++ b/objc/util/TINKStrings.h
@@ -31,3 +31,6 @@
/** Converts a absl::string_view to NSData. */
NSData* TINKStringViewToNSData(absl::string_view s);
+
+/** Converts a NSData to a std::string. */
+std::string NSDataToTINKString(NSData* data);
diff --git a/objc/util/TINKStrings.mm b/objc/util/TINKStrings.mm
index ab5880e..e74c0e0 100644
--- a/objc/util/TINKStrings.mm
+++ b/objc/util/TINKStrings.mm
@@ -40,3 +40,6 @@
return [NSData dataWithBytes:s.data() length:s.size()];
}
+std::string NSDataToTINKString(NSData* data) {
+ return std::string(static_cast<const char*>(data.bytes), data.length);
+}
diff --git a/objc/util/TINKTestHelpers.h b/objc/util/TINKTestHelpers.h
deleted file mode 100644
index 07503c0..0000000
--- a/objc/util/TINKTestHelpers.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- **************************************************************************
- */
-
-#include "absl/strings/string_view.h"
-
-#import "GPBMessage.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/EciesAeadHkdf.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
-
-TINKPBKeyset *TINKCreateKeyset(TINKPBKeyset_Key *primaryKey, TINKPBKeyset_Key *key1,
- TINKPBKeyset_Key *key2);
-
-void TINKAddKey(TINKPBKeyset_Key *key, TINKPBKeyset *keyset);
-
-void TINKAddKey(NSString *keyType, NSUInteger keyId, TINKPBKeyset *keyset);
-
-void TINKAddTinkKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset);
-
-void TINKAddLegacyKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset);
-
-void TINKAddRawKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset);
-
-TINKPBEciesAeadHkdfPrivateKey *TINKGetEciesAesGcmHkdfTestKey(TINKPBEllipticCurveType curveType,
- TINKPBEcPointFormat ecPointFormat,
- TINKPBHashType hashType,
- uint32_t aesGcmKeySize);
-
-TINKPBKeyset_Key *TINKCreateKey(NSString *keyType, uint32_t keyID, GPBMessage *newKey,
- TINKPBOutputPrefixType outputPrefix, TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType);
-
-TINKPBKeyset *TINKCreateKeyset(TINKPBKeyset_Key *primaryKey, TINKPBKeyset_Key *key1,
- TINKPBKeyset_Key *key2);
-
-/** Serializes an Obj-C protocol buffer to a C++ std::string. */
-std::string TINKPBSerializeToString(GPBMessage *message, NSError **error);
diff --git a/objc/util/TINKTestHelpers.mm b/objc/util/TINKTestHelpers.mm
deleted file mode 100644
index 8ad5c3f..0000000
--- a/objc/util/TINKTestHelpers.mm
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- **************************************************************************
- */
-
-#import "objc/util/TINKTestHelpers.h"
-
-#include "tink/subtle/common_enums.h"
-#include "tink/subtle/subtle_util_boringssl.h"
-
-#import <Foundation/Foundation.h>
-
-#import "GPBMessage.h"
-#import "GPBProtocolBuffers.h"
-#import "objc/util/TINKErrors.h"
-#import "objc/util/TINKStrings.h"
-#import "proto/AesGcm.pbobjc.h"
-#import "proto/Common.pbobjc.h"
-#import "proto/EciesAeadHkdf.pbobjc.h"
-#import "proto/Tink.pbobjc.h"
-
-TINKPBKeyset *TINKCreateKeyset(TINKPBKeyset_Key *primaryKey, TINKPBKeyset_Key *key1,
- TINKPBKeyset_Key *key2) {
- TINKPBKeyset *keyset = [[TINKPBKeyset alloc] init];
-
- TINKAddKey(primaryKey, keyset);
- TINKAddKey(key1, keyset);
- TINKAddKey(key2, keyset);
-
- keyset.primaryKeyId = [primaryKey keyId];
- return keyset;
-}
-
-TINKPBKeyset_Key *TINKCreateKey(NSString *keyType, uint32_t keyID, GPBMessage *newKey,
- TINKPBOutputPrefixType outputPrefix, TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType) {
- TINKPBKeyset_Key *key = [[TINKPBKeyset_Key alloc] init];
- key.outputPrefixType = outputPrefix;
- key.keyId = keyID;
- key.status = keyStatus;
-
- if (!key.hasKeyData) {
- key.keyData = [[TINKPBKeyData alloc] init];
- }
-
- key.keyData.typeURL = keyType;
- key.keyData.keyMaterialType = materialType;
- key.keyData.value = [newKey data];
- return key;
-}
-
-void TINKAddKey(NSString *keyType, uint32_t keyId, GPBMessage *keyMaterial,
- TINKPBOutputPrefixType outputPrefix, TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType, TINKPBKeyset *keyset) {
- TINKPBKeyset_Key *key =
- TINKCreateKey(keyType, keyId, keyMaterial, outputPrefix, keyStatus, materialType);
-
- TINKAddKey(key, keyset);
-}
-
-void TINKAddKey(TINKPBKeyset_Key *key, TINKPBKeyset *keyset) {
- if (!keyset.keyArray) {
- keyset.keyArray = [[NSMutableArray alloc] init];
- }
-
- NSMutableArray<TINKPBKeyset_Key *> *keyArray = [keyset keyArray];
-
- [keyArray addObject:key];
-}
-
-void TINKAddTinkKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset) {
- TINKAddKey(keyType, keyID, key, TINKPBOutputPrefixType_Tink, keyStatus, materialType, keyset);
-}
-
-void TINKAddLegacyKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset) {
- TINKAddKey(keyType, keyID, key, TINKPBOutputPrefixType_Legacy, keyStatus, materialType, keyset);
-}
-
-void TINKAddRawKey(NSString *keyType,
- uint32_t keyID,
- GPBMessage *key,
- TINKPBKeyStatusType keyStatus,
- TINKPBKeyData_KeyMaterialType materialType,
- TINKPBKeyset *keyset) {
- TINKAddKey(keyType, keyID, key, TINKPBOutputPrefixType_Raw, keyStatus, materialType, keyset);
-}
-
-TINKPBEciesAeadHkdfPrivateKey *TINKGetEciesAesGcmHkdfTestKey(TINKPBEllipticCurveType curveType,
- TINKPBEcPointFormat ecPointFormat,
- TINKPBHashType hashType,
- uint32_t aesGcmKeySize) {
- /* TODO(candrian): replace the static_cast below with an explicit translation */
- auto test_key = crypto::tink::subtle::SubtleUtilBoringSSL::GetNewEcKey(
- static_cast<crypto::tink::subtle::EllipticCurveType>(curveType))
- .ValueOrDie();
-
- TINKPBEciesAeadHkdfPrivateKey *eciesKey = [[TINKPBEciesAeadHkdfPrivateKey alloc] init];
- eciesKey.version = 0;
- eciesKey.keyValue = TINKStringToNSData(test_key.priv);
-
- if (!eciesKey.hasPublicKey) {
- eciesKey.publicKey = [[TINKPBEciesAeadHkdfPublicKey alloc] init];
- }
-
- TINKPBEciesAeadHkdfPublicKey *publicKey = eciesKey.publicKey;
- publicKey.version = 0;
- publicKey.x = TINKStringToNSData(test_key.pub_x);
- publicKey.y = TINKStringToNSData(test_key.pub_y);
-
- if (!publicKey.hasParams) {
- publicKey.params = [[TINKPBEciesAeadHkdfParams alloc] init];
- }
-
- TINKPBEciesAeadHkdfParams *params = publicKey.params;
- params.ecPointFormat = ecPointFormat;
-
- if (!params.hasKemParams) {
- params.kemParams = [[TINKPBEciesHkdfKemParams alloc] init];
- }
-
- TINKPBEciesHkdfKemParams *kemParams = params.kemParams;
- kemParams.curveType = curveType;
- kemParams.hkdfHashType = hashType;
-
- TINKPBAesGcmKeyFormat *keyFormat = [[TINKPBAesGcmKeyFormat alloc] init];
- keyFormat.keySize = 32;
-
- if (!params.hasDemParams) {
- params.demParams = [[TINKPBEciesAeadDemParams alloc] init];
- }
- TINKPBEciesAeadDemParams *demParams = params.demParams;
-
- if (!demParams.hasAeadDem) {
- demParams.aeadDem = [[TINKPBKeyTemplate alloc] init];
- }
-
- TINKPBKeyTemplate *aeadDem = demParams.aeadDem;
- aeadDem.typeURL = @"type.googleapis.com/google.crypto.tink.AesGcmKey";
- aeadDem.value = [keyFormat data];
-
- return eciesKey;
-}
-
-std::string TINKPBSerializeToString(GPBMessage *message, NSError **error) {
- NSData *serializedPB = [message data];
- if (!serializedPB) {
- if (error) {
- *error = TINKStatusToError(crypto::tink::util::Status(
- crypto::tink::util::error::INVALID_ARGUMENT, "Could not serialize message."));
- }
- return std::string("");
- }
- return std::string(static_cast<const char *>(serializedPB.bytes), serializedPB.length);
-}
diff --git a/proto/BUILD.bazel b/proto/BUILD.bazel
index 6879a8e..f4a2e1d 100644
--- a/proto/BUILD.bazel
+++ b/proto/BUILD.bazel
@@ -1,209 +1,146 @@
-load("//third_party/rules_protobuf/objc:rules.bzl", "objc_proto_compile")
-load("//tools:objc.bzl", "tink_objc_proto_library")
-load("@com_google_protobuf//:protobuf.bzl", "py_proto_library")
-
licenses(["notice"])
# -----------------------------------------------
# common
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "common_proto",
srcs = [
"common.proto",
],
-)
-
-objc_proto_compile(
- name = "common_objc_pb",
- protos = ["common.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# tink
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "tink_proto",
srcs = [
"tink.proto",
],
-)
-
-objc_proto_compile(
- name = "tink_objc_pb",
- protos = ["tink.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# config
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "config_proto",
srcs = [
"config.proto",
],
-)
-
-objc_proto_compile(
- name = "config_objc_pb",
- protos = ["config.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# aes-siv
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_siv_proto",
srcs = [
"aes_siv.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_siv_objc_pb",
- protos = ["aes_siv.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# rsa_ssa_pkcs1
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "rsa_ssa_pkcs1_proto",
srcs = [
"rsa_ssa_pkcs1.proto",
],
+ visibility = ["//visibility:public"],
deps = [
":common_proto",
],
)
-objc_proto_compile(
- name = "rsa_ssa_pkcs1_objc_pb",
- protos = ["rsa_ssa_pkcs1.proto"],
- tags = ["manual"],
- deps = [":common_objc_pb"],
-)
-
# -----------------------------------------------
# rsa_ssa_pss
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "rsa_ssa_pss_proto",
srcs = [
"rsa_ssa_pss.proto",
],
+ visibility = ["//visibility:public"],
deps = [
":common_proto",
],
)
-objc_proto_compile(
- name = "rsa_ssa_pss_objc_pb",
- protos = ["rsa_ssa_pss.proto"],
- tags = ["manual"],
- deps = [":common_objc_pb"],
-)
-
# -----------------------------------------------
# ecdsa
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "ecdsa_proto",
srcs = [
"ecdsa.proto",
],
+ visibility = ["//visibility:public"],
deps = [
":common_proto",
],
)
-objc_proto_compile(
- name = "ecdsa_objc_pb",
- protos = ["ecdsa.proto"],
- tags = ["manual"],
- deps = [":common_objc_pb"],
-)
-
# -----------------------------------------------
# ed25519
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "ed25519_proto",
srcs = [
"ed25519.proto",
],
-)
-
-objc_proto_compile(
- name = "ed25519_objc_pb",
- protos = ["ed25519.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# aes_cmac
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_cmac_proto",
srcs = [
"aes_cmac.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_cmac_objc_pb",
- protos = ["aes_cmac.proto"],
- tags = ["manual"],
- deps = [],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# hmac
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "hmac_proto",
srcs = [
"hmac.proto",
],
+ visibility = ["//visibility:public"],
deps = [":common_proto"],
)
-objc_proto_compile(
- name = "hmac_objc_pb",
- protos = ["hmac.proto"],
- tags = ["manual"],
- deps = [":common_objc_pb"],
+# -----------------------------------------------
+# JWS hmac
+# -----------------------------------------------
+proto_library(
+ name = "jws_hmac_proto",
+ srcs = [
+ "jws_hmac.proto",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [":common_proto"],
)
# -----------------------------------------------
# aes_ctr
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_ctr_proto",
srcs = [
"aes_ctr.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_ctr_objc_pb",
- protos = ["aes_ctr.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
@@ -211,336 +148,185 @@
# aes_ctr_hmac_aead
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_ctr_hmac_aead_proto",
srcs = [
"aes_ctr_hmac_aead.proto",
],
+ visibility = ["//visibility:public"],
deps = [
":aes_ctr_proto",
":hmac_proto",
],
)
-objc_proto_compile(
- name = "aes_ctr_hmac_aead_objc_pb",
- protos = ["aes_ctr_hmac_aead.proto"],
- tags = ["manual"],
- deps = [
- ":aes_ctr_objc_pb",
- ":hmac_objc_pb",
- ],
-)
-
# -----------------------------------------------
# aes_gcm
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_gcm_proto",
srcs = [
"aes_gcm.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_gcm_objc_pb",
- protos = ["aes_gcm.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# aes_gcm_siv
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_gcm_siv_proto",
srcs = [
"aes_gcm_siv.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_gcm_siv_objc_pb",
- protos = ["aes_gcm_siv.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# aes_ctr_hmac_streaming
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_ctr_hmac_streaming_proto",
srcs = ["aes_ctr_hmac_streaming.proto"],
+ visibility = ["//visibility:public"],
deps = [
":common_proto",
":hmac_proto",
],
)
-objc_proto_compile(
- name = "aes_ctr_hmac_streaming_objc_pb",
- protos = ["aes_ctr_hmac_streaming.proto"],
- tags = ["manual"],
- deps = [
- ":common_objc_pb",
- ":hmac_objc_pb",
- ],
-)
-
# -----------------------------------------------
# aes_gcm_hkdf_streaming
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_gcm_hkdf_streaming_proto",
srcs = ["aes_gcm_hkdf_streaming.proto"],
+ visibility = ["//visibility:public"],
deps = [":common_proto"],
)
-objc_proto_compile(
- name = "aes_gcm_hkdf_streaming_objc_pb",
- protos = ["aes_gcm_hkdf_streaming.proto"],
- tags = ["manual"],
- deps = [
- ":common_objc_pb",
- ],
-)
-
# -----------------------------------------------
# aes_eax
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_eax_proto",
srcs = [
"aes_eax.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_eax_objc_pb",
- protos = ["aes_eax.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# chacha20_poly1305
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "chacha20_poly1305_proto",
srcs = [
"chacha20_poly1305.proto",
],
-)
-
-objc_proto_compile(
- name = "chacha20_poly1305_objc_pb",
- protos = ["chacha20_poly1305.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# kms_aead
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "kms_aead_proto",
srcs = [
"kms_aead.proto",
],
-)
-
-objc_proto_compile(
- name = "kms_aead_objc_pb",
- protos = ["kms_aead.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# kms_envelope
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "kms_envelope_proto",
srcs = [
"kms_envelope.proto",
],
+ visibility = ["//visibility:public"],
deps = [":tink_proto"],
)
-objc_proto_compile(
- name = "kms_envelope_objc_pb",
- protos = ["kms_envelope.proto"],
- tags = ["manual"],
- deps = [
- ":tink_objc_pb",
- ],
-)
-
# -----------------------------------------------
# ecies_aead_hkdf
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "ecies_aead_hkdf_proto",
srcs = [
"ecies_aead_hkdf.proto",
],
+ visibility = ["//visibility:public"],
deps = [
":common_proto",
":tink_proto",
],
)
-objc_proto_compile(
- name = "ecies_aead_hkdf_objc_pb",
- protos = ["ecies_aead_hkdf.proto"],
- tags = ["manual"],
- deps = [
- ":common_objc_pb",
- ":tink_objc_pb",
- ],
-)
-
# -----------------------------------------------
# XChacha20 with Poly1305
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "xchacha20_poly1305_proto",
srcs = [
"xchacha20_poly1305.proto",
],
-)
-
-objc_proto_compile(
- name = "xchacha20_poly1305_objc_pb",
- protos = ["xchacha20_poly1305.proto"],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# Hkdf prf
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "hkdf_prf_proto",
srcs = [
"hkdf_prf.proto",
],
+ visibility = ["//visibility:public"],
deps = [":common_proto"],
)
-objc_proto_compile(
- name = "hkdf_prf_objc_pb",
- protos = ["hkdf_prf.proto"],
- tags = ["manual"],
-)
-
# -----------------------------------------------
# aes_cmac_prf
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "aes_cmac_prf_proto",
srcs = [
"aes_cmac_prf.proto",
],
-)
-
-objc_proto_compile(
- name = "aes_cmac_prf_objc_pb",
- protos = ["aes_cmac_prf.proto"],
- tags = ["manual"],
- deps = [],
+ visibility = ["//visibility:public"],
)
# -----------------------------------------------
# hmac_prf
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "hmac_prf_proto",
srcs = [
"hmac_prf.proto",
],
+ visibility = ["//visibility:public"],
deps = [":common_proto"],
)
-objc_proto_compile(
- name = "hmac_prf_objc_pb",
- protos = ["hmac_prf.proto"],
- tags = ["manual"],
- deps = [":common_objc_pb"],
-)
-
-
# ----------------------------------------------------------------------------
# prf_based_deriver
# ----------------------------------------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "prf_based_deriver_proto",
srcs = ["prf_based_deriver.proto"],
+ visibility = ["//visibility:public"],
deps = [":tink_proto"],
)
-objc_proto_compile(
- name = "prf_based_deriver_objc_pb",
- protos = ["prf_based_deriver.proto"],
- tags = ["manual"],
-)
-
# -----------------------------------------------
# empty
# -----------------------------------------------
proto_library(
- visibility = ["//visibility:public"],
name = "empty_proto",
srcs = [
"empty.proto",
],
-)
-
-objc_proto_compile(
- name = "empty_objc_pb",
- protos = ["empty.proto"],
- tags = ["manual"],
-)
-
-# -----------------------------------------------
-# objc library
-# -----------------------------------------------
-tink_objc_proto_library(
- name = "all_objc_proto",
- srcs = [
- ":aes_cmac_objc_pb",
- ":aes_cmac_prf_objc_pb",
- ":aes_ctr_hmac_aead_objc_pb",
- ":aes_ctr_hmac_streaming_objc_pb",
- ":aes_ctr_objc_pb",
- ":aes_eax_objc_pb",
- ":aes_gcm_hkdf_streaming_objc_pb",
- ":aes_gcm_objc_pb",
- ":aes_siv_objc_pb",
- ":chacha20_poly1305_objc_pb",
- ":common_objc_pb",
- ":config_objc_pb",
- ":ecdsa_objc_pb",
- ":ecies_aead_hkdf_objc_pb",
- ":ed25519_objc_pb",
- ":empty_objc_pb",
- ":hmac_objc_pb",
- ":hmac_prf_objc_pb",
- ":kms_aead_objc_pb",
- ":kms_envelope_objc_pb",
- ":rsa_ssa_pkcs1_objc_pb",
- ":rsa_ssa_pss_objc_pb",
- ":tink_objc_pb",
- ":xchacha20_poly1305_objc_pb",
- ],
- tags = ["manual"],
+ visibility = ["//visibility:public"],
)
diff --git a/proto/aes_cmac.proto b/proto/aes_cmac.proto
index ee150c4..b214834 100644
--- a/proto/aes_cmac.proto
+++ b/proto/aes_cmac.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_cmac_go_proto";
message AesCmacParams {
diff --git a/proto/aes_cmac_prf.proto b/proto/aes_cmac_prf.proto
index de8f32a..cd75015 100644
--- a/proto/aes_cmac_prf.proto
+++ b/proto/aes_cmac_prf.proto
@@ -18,7 +18,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_cmac_prf_go_proto";
// key_type: type.googleapis.com/google.crypto.tink.AesCmacPrfKey
diff --git a/proto/aes_ctr.proto b/proto/aes_ctr.proto
index 27c9d4e..ecdb256 100644
--- a/proto/aes_ctr.proto
+++ b/proto/aes_ctr.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_go_proto";
message AesCtrParams {
diff --git a/proto/aes_ctr_hmac_aead.proto b/proto/aes_ctr_hmac_aead.proto
index 065de8c..dcf541d 100644
--- a/proto/aes_ctr_hmac_aead.proto
+++ b/proto/aes_ctr_hmac_aead.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_hmac_aead_go_proto";
message AesCtrHmacAeadKeyFormat {
diff --git a/proto/aes_ctr_hmac_streaming.proto b/proto/aes_ctr_hmac_streaming.proto
index b4a3d94..8425424 100644
--- a/proto/aes_ctr_hmac_streaming.proto
+++ b/proto/aes_ctr_hmac_streaming.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_hmac_streaming_go_proto";
message AesCtrHmacStreamingParams {
diff --git a/proto/aes_eax.proto b/proto/aes_eax.proto
index d84ad2a..c673306 100644
--- a/proto/aes_eax.proto
+++ b/proto/aes_eax.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_eax_go_proto";
// only allowing tag size in bytes = 16
diff --git a/proto/aes_gcm.proto b/proto/aes_gcm.proto
index 2a0c584..ca1483f 100644
--- a/proto/aes_gcm.proto
+++ b/proto/aes_gcm.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_go_proto";
// only allowing IV size in bytes = 12 and tag size in bytes = 16
diff --git a/proto/aes_gcm_hkdf_streaming.proto b/proto/aes_gcm_hkdf_streaming.proto
index 1189ebc..61fb479 100644
--- a/proto/aes_gcm_hkdf_streaming.proto
+++ b/proto/aes_gcm_hkdf_streaming.proto
@@ -19,11 +19,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_hkdf_streaming_go_proto";
message AesGcmHkdfStreamingParams {
diff --git a/proto/aes_gcm_siv.proto b/proto/aes_gcm_siv.proto
index 2824a54..d97d191 100644
--- a/proto/aes_gcm_siv.proto
+++ b/proto/aes_gcm_siv.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_siv_go_proto";
// The only allowed IV size is 12 bytes and tag size is 16 bytes.
diff --git a/proto/aes_siv.proto b/proto/aes_siv.proto
index 6442587..ae4bdfe 100644
--- a/proto/aes_siv.proto
+++ b/proto/aes_siv.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_siv_go_proto";
message AesSivKeyFormat {
diff --git a/proto/chacha20_poly1305.proto b/proto/chacha20_poly1305.proto
index 57ec1ca..2cd6ead 100644
--- a/proto/chacha20_poly1305.proto
+++ b/proto/chacha20_poly1305.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/chacha20_poly1305_go_proto";
message ChaCha20Poly1305KeyFormat {}
diff --git a/proto/common.proto b/proto/common.proto
index 2c640a9..d5862d5 100644
--- a/proto/common.proto
+++ b/proto/common.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/common_go_proto";
enum EllipticCurveType {
diff --git a/proto/config.proto b/proto/config.proto
index 4017053..ebbd742 100644
--- a/proto/config.proto
+++ b/proto/config.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/config_go_proto";
// An entry that describes a key type to be used with Tink library,
@@ -31,12 +30,12 @@
// KeyTypeEntry is no longer supported.
option deprecated = true;
- string primitive_name = 1; // E.g. “Aead”, “Mac”, ... (case-insensitive)
- string type_url = 2; // Name of the key type.
+ string primitive_name = 1; // E.g. “Aead”, “Mac”, ... (case-insensitive)
+ string type_url = 2; // Name of the key type.
uint32 key_manager_version = 3; // Minimum required version of key manager.
bool new_key_allowed = 4; // Can the key manager create new keys?
- string catalogue_name = 5; // Catalogue to be queried for key manager,
- // e.g. "Tink", "Custom", ... (case-insensitive)
+ string catalogue_name = 5; // Catalogue to be queried for key manager,
+ // e.g. "Tink", "Custom", ... (case-insensitive)
}
// A complete configuration of Tink library: a list of key types
diff --git a/proto/ecdsa.proto b/proto/ecdsa.proto
index e7c9af8..6ba3970 100644
--- a/proto/ecdsa.proto
+++ b/proto/ecdsa.proto
@@ -18,18 +18,18 @@
syntax = "proto3";
package google.crypto.tink;
+
import "proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ecdsa_go_proto";
enum EcdsaSignatureEncoding {
UNKNOWN_ENCODING = 0;
- // The signature's format is r || s, where r and s are zero-padded and have the same size in
- // bytes as the order of the curve. For example, for NIST P-256 curve, r and s are zero-padded to
- // 32 bytes.
+ // The signature's format is r || s, where r and s are zero-padded and have
+ // the same size in bytes as the order of the curve. For example, for NIST
+ // P-256 curve, r and s are zero-padded to 32 bytes.
IEEE_P1363 = 1;
// The signature is encoded using ASN.1
// (https://tools.ietf.org/html/rfc5480#appendix-A):
diff --git a/proto/ecies_aead_hkdf.proto b/proto/ecies_aead_hkdf.proto
index e0caa83..b73d17d 100644
--- a/proto/ecies_aead_hkdf.proto
+++ b/proto/ecies_aead_hkdf.proto
@@ -18,25 +18,29 @@
syntax = "proto3";
package google.crypto.tink;
+
import "proto/common.proto";
import "proto/tink.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ecies_aead_hkdf_go_proto";
// Protos for keys for ECIES with HKDF and AEAD encryption.
//
// These definitions follow loosely ECIES ISO 18033-2 standard
-// (Elliptic Curve Integrated Encryption Scheme, see http://www.shoup.net/iso/std6.pdf),
-// with but with some differences:
-// * use of HKDF key derivation function (instead of KDF1 and KDF2) enabling the use
-// of optional parameters to the key derivation function, which strenghten the overall
-// security and allow for binding the key material to application-specific information
-// (cf. RFC 5869, https://tools.ietf.org/html/rfc5869)
-// * use of modern AEAD schemes rather than "manual composition" of symmetric encryption
-// with message authentication codes (as in DEM1, DEM2, and DEM3 schemes of ISO 18033-2)
+// (Elliptic Curve Integrated Encryption Scheme, see
+// http://www.shoup.net/iso/std6.pdf), with but with some differences:
+// * use of HKDF key derivation function (instead of KDF1 and KDF2) enabling
+// the use
+// of optional parameters to the key derivation function, which strenghten
+// the overall security and allow for binding the key material to
+// application-specific information (cf. RFC 5869,
+// https://tools.ietf.org/html/rfc5869)
+// * use of modern AEAD schemes rather than "manual composition" of symmetric
+// encryption
+// with message authentication codes (as in DEM1, DEM2, and DEM3 schemes of
+// ISO 18033-2)
//
// ECIES-keys represent HybridEncryption resp. HybridDecryption primitives.
@@ -55,7 +59,8 @@
// Parameters of AEAD DEM (Data Encapsulation Mechanism).
message EciesAeadDemParams {
// Required.
- KeyTemplate aead_dem = 2; // Contains e.g. AesCtrHmacAeadKeyFormat or AesGcmKeyFormat.
+ KeyTemplate aead_dem =
+ 2; // Contains e.g. AesCtrHmacAeadKeyFormat or AesGcmKeyFormat.
}
message EciesAeadHkdfParams {
@@ -81,8 +86,8 @@
EciesAeadHkdfParams params = 2;
// Affine coordinates of the public key in bigendian representation.
- // The public key is a point (x, y) on the curve defined by params.kem_params.curve.
- // Required.
+ // The public key is a point (x, y) on the curve defined by
+ // params.kem_params.curve. Required.
bytes x = 3;
// Required.
bytes y = 4;
diff --git a/proto/ed25519.proto b/proto/ed25519.proto
index 19b8789..93a5d7d 100644
--- a/proto/ed25519.proto
+++ b/proto/ed25519.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ed25519_go_proto";
message Ed25519KeyFormat {}
diff --git a/proto/empty.proto b/proto/empty.proto
index 757b6e2..33831a9 100644
--- a/proto/empty.proto
+++ b/proto/empty.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/empty_go_proto";
message Empty {}
diff --git a/proto/hkdf_prf.proto b/proto/hkdf_prf.proto
index cfafdc0..7a83050 100644
--- a/proto/hkdf_prf.proto
+++ b/proto/hkdf_prf.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hkdf_prf_proto";
message HkdfPrfParams {
diff --git a/proto/hmac.proto b/proto/hmac.proto
index 7e07589..2733e51 100644
--- a/proto/hmac.proto
+++ b/proto/hmac.proto
@@ -22,11 +22,10 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hmac_go_proto";
message HmacParams {
- HashType hash = 1; // HashType is an enum.
+ HashType hash = 1; // HashType is an enum.
uint32 tag_size = 2;
}
diff --git a/proto/hmac_prf.proto b/proto/hmac_prf.proto
index f074da2..189f303 100644
--- a/proto/hmac_prf.proto
+++ b/proto/hmac_prf.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hmac_prf_go_proto";
message HmacPrfParams {
diff --git a/proto/jws_hmac.proto b/proto/jws_hmac.proto
new file mode 100644
index 0000000..a3dc296
--- /dev/null
+++ b/proto/jws_hmac.proto
@@ -0,0 +1,36 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+syntax = "proto3";
+
+package google.crypto.tink;
+
+import "proto/common.proto";
+
+option java_package = "com.google.crypto.tink.proto";
+option java_multiple_files = true;
+option go_package = "github.com/google/tink/proto/jws_hmac_go_proto";
+
+// key_type: type.googleapis.com/google.crypto.tink.JwsHmacKey
+message JwsHmacKey {
+ uint32 version = 1;
+ HashType hash_type = 2;
+ bytes key_value = 3;
+}
+
+message JwsHmacKeyFormat {
+ uint32 version = 1;
+ HashType hash_type = 2;
+ uint32 key_size = 3;
+}
diff --git a/proto/kms_aead.proto b/proto/kms_aead.proto
index b7e077c..e818788 100644
--- a/proto/kms_aead.proto
+++ b/proto/kms_aead.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/kms_aead_go_proto";
message KmsAeadKeyFormat {
diff --git a/proto/kms_envelope.proto b/proto/kms_envelope.proto
index 991f412..fa806e6 100644
--- a/proto/kms_envelope.proto
+++ b/proto/kms_envelope.proto
@@ -22,7 +22,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/kms_envelope_go_proto";
message KmsEnvelopeAeadKeyFormat {
diff --git a/proto/prf_based_deriver.proto b/proto/prf_based_deriver.proto
index 8dfdcd4..074b54d 100644
--- a/proto/prf_based_deriver.proto
+++ b/proto/prf_based_deriver.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/prf_based_deriver_go_proto";
message PrfBasedDeriverParams {
diff --git a/proto/rsa_ssa_pkcs1.proto b/proto/rsa_ssa_pkcs1.proto
index 6a4fa60..961189d 100644
--- a/proto/rsa_ssa_pkcs1.proto
+++ b/proto/rsa_ssa_pkcs1.proto
@@ -19,11 +19,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/rsa_ssa_pkcs1_go_proto";
message RsaSsaPkcs1Params {
diff --git a/proto/rsa_ssa_pss.proto b/proto/rsa_ssa_pss.proto
index ecebeee..8e7903f 100644
--- a/proto/rsa_ssa_pss.proto
+++ b/proto/rsa_ssa_pss.proto
@@ -20,11 +20,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/rsa_ssa_pss_go_proto";
message RsaSsaPssParams {
diff --git a/proto/testing/BUILD.bazel b/proto/testing/BUILD.bazel
new file mode 100644
index 0000000..a6bd574
--- /dev/null
+++ b/proto/testing/BUILD.bazel
@@ -0,0 +1,11 @@
+licenses(["notice"])
+
+package(
+ default_testonly = 1,
+)
+
+proto_library(
+ name = "testing_api_proto",
+ srcs = ["testing_api.proto"],
+ visibility = ["//visibility:public"],
+)
diff --git a/proto/testing/testing_api.proto b/proto/testing/testing_api.proto
new file mode 100644
index 0000000..2c0dde4
--- /dev/null
+++ b/proto/testing/testing_api.proto
@@ -0,0 +1,288 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto3";
+
+package tink_testing_api;
+
+option java_package = "com.google.crypto.tink.proto.testing";
+option java_multiple_files = true;
+
+// Service providing metadata about the server.
+service Metadata {
+ // Returns some server information. A test may use this information to verify
+ // that it is talking to the right server.
+ rpc GetServerInfo(ServerInfoRequest) returns (ServerInfoResponse) {}
+}
+
+message ServerInfoRequest {}
+
+message ServerInfoResponse {
+ string tink_version = 1; // For example '1.4'
+ string language = 2; // For example 'cc', 'java', 'go' or 'python'.
+}
+
+// Service for Keyset operations.
+service Keyset {
+ // Generates a new keyset from a template.
+ rpc Generate(KeysetGenerateRequest) returns (KeysetGenerateResponse) {}
+ // Generates a public-key keyset from a private-key keyset.
+ rpc Public(KeysetPublicRequest) returns (KeysetPublicResponse) {}
+ // Converts a Keyset from Binary to Json Format
+ rpc ToJson(KeysetToJsonRequest) returns (KeysetToJsonResponse) {}
+ // Converts a Keyset from Json to Binary Format
+ rpc FromJson(KeysetFromJsonRequest) returns (KeysetFromJsonResponse) {}
+}
+
+message KeysetGenerateRequest {
+ bytes template = 1; // serialized google.crypto.tink.KeyTemplate.
+}
+
+message KeysetGenerateResponse {
+ oneof result {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+message KeysetPublicRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+}
+
+message KeysetPublicResponse {
+ oneof result {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+message KeysetToJsonRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+}
+
+message KeysetToJsonResponse {
+ oneof result {
+ string json_keyset = 1;
+ string err = 2;
+ }
+}
+
+message KeysetFromJsonRequest {
+ string json_keyset = 1;
+}
+
+message KeysetFromJsonResponse {
+ oneof result {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+// Service for AEAD encryption and decryption
+service Aead {
+ // Encrypts a plaintext with the provided keyset
+ rpc Encrypt(AeadEncryptRequest) returns (AeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc Decrypt(AeadDecryptRequest) returns (AeadDecryptResponse) {}
+}
+
+message AeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message AeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message AeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message AeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service for Deterministic AEAD encryption and decryption
+service DeterministicAead {
+ // Encrypts a plaintext with the provided keyset
+ rpc EncryptDeterministically(DeterministicAeadEncryptRequest)
+ returns (DeterministicAeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc DecryptDeterministically(DeterministicAeadDecryptRequest)
+ returns (DeterministicAeadDecryptResponse) {
+ }
+}
+
+message DeterministicAeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message DeterministicAeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message DeterministicAeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message DeterministicAeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service for Streaming AEAD encryption and decryption
+service StreamingAead {
+ // Encrypts a plaintext with the provided keyset
+ rpc Encrypt(StreamingAeadEncryptRequest)
+ returns (StreamingAeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc Decrypt(StreamingAeadDecryptRequest)
+ returns (StreamingAeadDecryptResponse) {}
+}
+
+message StreamingAeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message StreamingAeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message StreamingAeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message StreamingAeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service to compute and verify MACs
+service Mac {
+ // Computes a MAC for given data
+ rpc ComputeMac(ComputeMacRequest) returns (ComputeMacResponse) {}
+ // Verifies the validity of the MAC value, no error means success
+ rpc VerifyMac(VerifyMacRequest) returns (VerifyMacResponse) {}
+}
+
+message ComputeMacRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes data = 2;
+}
+
+message ComputeMacResponse {
+ oneof result {
+ bytes mac_value = 1;
+ string err = 2;
+ }
+}
+
+message VerifyMacRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes mac_value = 2;
+ bytes data = 3;
+}
+
+message VerifyMacResponse {
+ string err = 1;
+}
+
+// Service to hybrid encrypt and decrypt
+service Hybrid {
+ // Encrypts plaintext binding context_info to the resulting ciphertext
+ rpc Encrypt(HybridEncryptRequest) returns (HybridEncryptResponse) {}
+ // Decrypts ciphertext verifying the integrity of context_info
+ rpc Decrypt(HybridDecryptRequest) returns (HybridDecryptResponse) {}
+}
+
+message HybridEncryptRequest {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes context_info = 3;
+}
+
+message HybridEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message HybridDecryptRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes context_info = 3;
+}
+
+message HybridDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service to sign and verify signatures.
+service Signature {
+ // Computes the signature for data
+ rpc Sign(SignatureSignRequest) returns (SignatureSignResponse) {}
+ // Verifies that signature is a digital signature for data
+ rpc Verify(SignatureVerifyRequest) returns (SignatureVerifyResponse) {}
+}
+
+message SignatureSignRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes data = 2;
+}
+
+message SignatureSignResponse {
+ oneof result {
+ bytes signature = 1;
+ string err = 2;
+ }
+}
+
+message SignatureVerifyRequest {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes signature = 2;
+ bytes data = 3;
+}
+
+message SignatureVerifyResponse {
+ string err = 1;
+}
diff --git a/proto/tink.proto b/proto/tink.proto
index cfc125f..743906d 100644
--- a/proto/tink.proto
+++ b/proto/tink.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/tink_go_proto";
// Each instantiation of a Tink primitive is identified by type_url,
@@ -54,7 +53,7 @@
string type_url = 1; // in format type.googleapis.com/packagename.messagename
// Optional.
// If missing, it means the key type doesn't require a *KeyFormat proto.
- bytes value = 2; // contains specific serialized *KeyFormat proto
+ bytes value = 2; // contains specific serialized *KeyFormat proto
// Optional.
// If missing, uses OutputPrefixType.TINK.
OutputPrefixType output_prefix_type = 3;
@@ -112,13 +111,13 @@
// Required.
string type_url = 1; // In format type.googleapis.com/packagename.messagename
// Required.
- bytes value = 2; // contains specific serialized *Key proto
+ bytes value = 2; // contains specific serialized *Key proto
enum KeyMaterialType {
UNKNOWN_KEYMATERIAL = 0;
SYMMETRIC = 1;
ASYMMETRIC_PRIVATE = 2;
ASYMMETRIC_PUBLIC = 3;
- REMOTE = 4; // points to a remote key, i.e., in a KMS.
+ REMOTE = 4; // points to a remote key, i.e., in a KMS.
}
// Required.
KeyMaterialType key_material_type = 3;
@@ -130,7 +129,6 @@
// Any given keyset (and any given key) can be used for one primitive only.
message Keyset {
message Key {
-
// Contains the actual, instantiation specific key proto.
// By convention, each key proto contains a version field.
KeyData key_data = 1;
diff --git a/proto/xchacha20_poly1305.proto b/proto/xchacha20_poly1305.proto
index 353814c..29d3938 100644
--- a/proto/xchacha20_poly1305.proto
+++ b/proto/xchacha20_poly1305.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/xchacha20_poly1305_go_proto";
message XChaCha20Poly1305KeyFormat {}
diff --git a/python/setup.py b/python/setup.py
index a4513b7..aed66e4 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -15,17 +15,19 @@
from __future__ import division
from __future__ import print_function
+from distutils import spawn
import glob
import os
import posixpath
+import re
import shutil
import subprocess
import sys
-from distutils import spawn
import setuptools
from setuptools.command import build_ext
+
here = os.path.dirname(os.path.abspath(__file__))
@@ -105,40 +107,56 @@
Returns:
The workspace_content using http_archive for tink_base and tink_cc.
"""
- # Add http_archive load
- workspace_lines = workspace_content.split('\n')
- http_archive_load = ('load("@bazel_tools//tools/build_defs/repo:http.bzl", '
- '"http_archive")')
- workspace_content = '\n'.join([workspace_lines[0], http_archive_load] +
- workspace_lines[1:])
+ # This is run by pip from a temporary folder which breaks the WORKSPACE paths.
+ # This replaces the paths with the latest http_archive.
+ # In order to override this with a local WORKSPACE use the
+ # TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH environment variable.
- # Replace local with http archives
- base = ('local_repository(\n'
- ' name = "tink_base",\n'
- ' path = "..",\n'
+ if 'TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH' in os.environ:
+ base_path = os.environ['TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH']
+ workspace_content = re.sub(r'(?<="tink_base",\n path = ").*(?=\n)',
+ base_path + '", # Modified by setup.py',
+ workspace_content)
+ workspace_content = re.sub(r'(?<="tink_cc",\n path = ").*(?=\n)',
+ base_path + '/cc' + '", # Modified by setup.py',
+ workspace_content)
+ else:
+ # If not base is specified use the latest version from GitHub
+ # Add http_archive load
+ workspace_lines = workspace_content.split('\n')
+ http_archive_load = ('load("@bazel_tools//tools/build_defs/repo:http.bzl", '
+ '"http_archive")')
+ workspace_content = '\n'.join([workspace_lines[0], http_archive_load] +
+ workspace_lines[1:])
+
+ base = ('local_repository(\n'
+ ' name = "tink_base",\n'
+ ' path = "..",\n'
+ ')\n')
+
+ cc = ('local_repository(\n'
+ ' name = "tink_cc",\n'
+ ' path = "../cc",\n'
')\n')
- cc = ('local_repository(\n'
- ' name = "tink_cc",\n'
- ' path = "../cc",\n'
+ base_patched = (
+ '# Modified by setup.py\n'
+ 'http_archive(\n'
+ ' name = "tink_base",\n'
+ ' urls = ["https://github.com/google/tink/archive/master.zip"],\n'
+ ' strip_prefix = "tink-master/",\n'
')\n')
- base_http = (
- 'http_archive(\n'
- ' name = "tink_base",\n'
- ' urls = ["https://github.com/google/tink/archive/master.zip"],\n'
- ' strip_prefix = "tink-master/",\n'
- ')\n')
+ cc_patched = (
+ '# Modified by setup.py\n'
+ 'http_archive(\n'
+ ' name = "tink_cc",\n'
+ ' urls = ["https://github.com/google/tink/archive/master.zip"],\n'
+ ' strip_prefix = "tink-master/cc",\n'
+ ')\n')
- cc_http = (
- 'http_archive(\n'
- ' name = "tink_cc",\n'
- ' urls = ["https://github.com/google/tink/archive/master.zip"],\n'
- ' strip_prefix = "tink-master/cc",\n'
- ')\n')
-
- workspace_content = workspace_content.replace(base, base_http)
- workspace_content = workspace_content.replace(cc, cc_http)
+ workspace_content = workspace_content.replace(base, base_patched)
+ workspace_content = workspace_content.replace(cc, cc_patched)
return workspace_content
@@ -175,10 +193,11 @@
os.makedirs(self.build_temp)
bazel_argv = [
- bazel,
- 'build',
- ext.bazel_target,
+ bazel, 'build', ext.bazel_target,
'--compilation_mode=' + ('dbg' if self.debug else 'opt'),
+ '--incompatible_linkopts_to_linklibs'
+ # TODO(https://github.com/bazelbuild/bazel/issues/9254): Remove linkopts
+ # flag when issue is fixed.
]
self.spawn(bazel_argv)
ext_bazel_bin_path = os.path.join('bazel-bin', ext.relpath,
@@ -212,6 +231,7 @@
# PyPI package information.
classifiers=[
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Topic :: Software Development :: Libraries',
],
license='Apache 2.0',
diff --git a/python/tink/_keyset_handle.py b/python/tink/_keyset_handle.py
index 2547b97..6cfeafe 100644
--- a/python/tink/_keyset_handle.py
+++ b/python/tink/_keyset_handle.py
@@ -47,6 +47,7 @@
('KeysetHandle cannot be instantiated directly.'))
def __init__(self, keyset: tink_pb2.Keyset):
+ _validate_keyset(keyset)
self._keyset = keyset
@classmethod
diff --git a/python/tink/_keyset_handle_test.py b/python/tink/_keyset_handle_test.py
index 28e0ca8..228ef70 100644
--- a/python/tink/_keyset_handle_test.py
+++ b/python/tink/_keyset_handle_test.py
@@ -202,55 +202,51 @@
aead_primitive.decrypt(
aead_primitive.encrypt(b'message', b'aad'), b'aad'), b'message')
- def test_primitive_fails_on_empty_keyset(self):
+ def test_init_fails_on_empty_keyset(self):
keyset = tink_pb2.Keyset()
keyset.key.extend([helper.fake_key(key_id=1, status=tink_pb2.DESTROYED)])
keyset.primary_key_id = 1
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'empty keyset'):
- handle.primitive(aead.Aead)
+ _ = _keyset_handle(keyset)
- def test_primitive_fails_on_key_without_keydata(self):
+ def test_init_fails_on_key_without_keydata(self):
keyset = tink_pb2.Keyset()
key = helper.fake_key(key_id=123)
key.ClearField('key_data')
keyset.key.extend([key])
keyset.primary_key_id = 123
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 123 has no key data'):
+ handle = _keyset_handle(keyset)
handle.primitive(aead.Aead)
- def test_primitive_fails_on_key_with_unknown_prefix(self):
+ def test_init_fails_on_key_with_unknown_prefix(self):
keyset = tink_pb2.Keyset()
keyset.key.extend([
helper.fake_key(key_id=12, output_prefix_type=tink_pb2.UNKNOWN_PREFIX)
])
keyset.primary_key_id = 12
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 12 has unknown prefix'):
- handle.primitive(aead.Aead)
+ _ = _keyset_handle(keyset)
- def test_primitive_fails_on_key_with_unknown_status(self):
+ def test_init_fails_on_key_with_unknown_status(self):
keyset = tink_pb2.Keyset()
keyset.key.extend(
[helper.fake_key(key_id=1234, status=tink_pb2.UNKNOWN_STATUS)])
keyset.primary_key_id = 1234
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 1234 has unknown status'):
- handle.primitive(aead.Aead)
+ _ = _keyset_handle(keyset)
- def test_primitive_fails_on_multiple_primary_keys(self):
+ def test_init_fails_on_multiple_primary_keys(self):
keyset = tink_pb2.Keyset()
keyset.key.extend(
[helper.fake_key(key_id=12345),
helper.fake_key(key_id=12345)])
keyset.primary_key_id = 12345
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError,
'keyset contains multiple primary keys'):
- handle.primitive(aead.Aead)
+ _ = _keyset_handle(keyset)
- def test_primitive_fails_without_primary_key_present(self):
+ def test_init_fails_without_primary_key_present(self):
keyset = tink_pb2.Keyset()
key = keyset.key.add()
key.key_data.CopyFrom(
@@ -259,10 +255,9 @@
key.key_id = 2
key.status = tink_pb2.ENABLED
keyset.primary_key_id = 1
- handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError,
'keyset does not contain a valid primary key'):
- handle.primitive(aead.Aead)
+ _ = _keyset_handle(keyset)
def test_primitive_fails_on_wrong_primitive_class(self):
keyset = tink_pb2.Keyset()
@@ -300,7 +295,7 @@
aead_primitive2.encrypt(b'message', b'aad'), b'aad'), b'message')
def test_keyset_info(self):
- keyset = tink_pb2.Keyset(primary_key_id=2)
+ keyset = tink_pb2.Keyset(primary_key_id=1)
keyset.key.extend([
helper.fake_key(
value=b'v1',
@@ -316,7 +311,7 @@
output_prefix_type=tink_pb2.RAW)
])
handle = _keyset_handle(keyset)
- expected_keyset_info = tink_pb2.KeysetInfo(primary_key_id=2)
+ expected_keyset_info = tink_pb2.KeysetInfo(primary_key_id=1)
info1 = expected_keyset_info.key_info.add()
info1.type_url = 't1'
info1.status = tink_pb2.ENABLED
diff --git a/python/tink/_keyset_reader.py b/python/tink/_keyset_reader.py
index 29b901e..63e9672 100644
--- a/python/tink/_keyset_reader.py
+++ b/python/tink/_keyset_reader.py
@@ -20,10 +20,11 @@
from __future__ import print_function
import abc
+
+from typing import Text
# Special imports
import six
-from typing import Text
from tink.proto import tink_pb2
from tink import core
@@ -38,12 +39,12 @@
@abc.abstractmethod
def read(self) -> tink_pb2.Keyset:
"""Reads and returns a (cleartext) tink_pb2.Keyset from its source."""
- pass
+ raise NotImplementedError()
@abc.abstractmethod
def read_encrypted(self) -> tink_pb2.EncryptedKeyset:
"""Reads and returns an tink_pb2.EncryptedKeyset from its source."""
- pass
+ raise NotImplementedError()
class JsonKeysetReader(KeysetReader):
diff --git a/python/tink/_keyset_reader_test.py b/python/tink/_keyset_reader_test.py
index 8fef028..83fe54d 100644
--- a/python/tink/_keyset_reader_test.py
+++ b/python/tink/_keyset_reader_test.py
@@ -18,9 +18,9 @@
from __future__ import division
from __future__ import print_function
+from typing import cast
from absl.testing import absltest
-from typing import cast
from tink.proto import tink_pb2
import tink
from tink import core
@@ -102,17 +102,17 @@
self.assertEqual(keyset, reader.read())
def test_read_none(self):
- with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(cast(bytes, None))
reader.read()
def test_read_empty(self):
- with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(b'')
reader.read()
def test_read_invalid(self):
- with self.assertRaisesRegex(core.TinkError, 'Wrong wire type'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(b'some weird data')
reader.read()
@@ -130,17 +130,17 @@
self.assertEqual(encrypted_keyset, reader.read_encrypted())
def test_read_encrypted_none(self):
- with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(cast(bytes, None))
reader.read_encrypted()
def test_read_encrypted_empty(self):
- with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(b'')
reader.read_encrypted()
def test_read_encrypted_invalid(self):
- with self.assertRaisesRegex(core.TinkError, 'Wrong wire type'):
+ with self.assertRaises(core.TinkError):
reader = tink.BinaryKeysetReader(b'some weird data')
reader.read_encrypted()
diff --git a/python/tink/_keyset_writer.py b/python/tink/_keyset_writer.py
index c2b4cd5..b62a152 100644
--- a/python/tink/_keyset_writer.py
+++ b/python/tink/_keyset_writer.py
@@ -21,10 +21,10 @@
import abc
+from typing import BinaryIO, TextIO
# Special imports
import six
-from typing import BinaryIO, TextIO
from google.protobuf import json_format
from tink.proto import tink_pb2
from tink import core
@@ -37,12 +37,12 @@
@abc.abstractmethod
def write(self, keyset: tink_pb2.Keyset) -> None:
"""Tries to write a tink_pb2.Keyset to some storage system."""
- pass
+ raise NotImplementedError()
@abc.abstractmethod
def write_encrypted(self, encrypted_keyset: tink_pb2.EncryptedKeyset) -> None:
"""Tries to write an tink_pb2.EncryptedKeyset to some storage system."""
- pass
+ raise NotImplementedError()
class JsonKeysetWriter(KeysetWriter):
diff --git a/python/tink/_keyset_writer_test.py b/python/tink/_keyset_writer_test.py
index 89d0397..44cf6e1 100644
--- a/python/tink/_keyset_writer_test.py
+++ b/python/tink/_keyset_writer_test.py
@@ -21,8 +21,9 @@
import io
-from absl.testing import absltest
from typing import cast
+from absl.testing import absltest
+
from tink.proto import tink_pb2
import tink
from tink import core
diff --git a/python/tink/aead/BUILD.bazel b/python/tink/aead/BUILD.bazel
index 32a134c..9b0e9ff 100644
--- a/python/tink/aead/BUILD.bazel
+++ b/python/tink/aead/BUILD.bazel
@@ -46,10 +46,14 @@
deps = [
":aead",
requirement("absl-py"),
+ "//tink:tink_python",
"//tink/core",
+ "//tink/proto:aes_ctr_hmac_aead_py_pb2",
"//tink/proto:aes_eax_py_pb2",
"//tink/proto:aes_gcm_py_pb2",
+ "//tink/proto:common_py_pb2",
"//tink/proto:tink_py_pb2",
+ "//tink/proto:xchacha20_poly1305_py_pb2",
],
)
diff --git a/python/tink/aead/_aead_key_manager_test.py b/python/tink/aead/_aead_key_manager_test.py
index e0604d4..6301002 100644
--- a/python/tink/aead/_aead_key_manager_test.py
+++ b/python/tink/aead/_aead_key_manager_test.py
@@ -19,9 +19,14 @@
from __future__ import print_function
from absl.testing import absltest
+from absl.testing import parameterized
+from tink.proto import aes_ctr_hmac_aead_pb2
from tink.proto import aes_eax_pb2
from tink.proto import aes_gcm_pb2
+from tink.proto import common_pb2
from tink.proto import tink_pb2
+from tink.proto import xchacha20_poly1305_pb2
+import tink
from tink import aead
from tink import core
@@ -30,47 +35,14 @@
aead.register()
-class AeadKeyManagerTest(absltest.TestCase):
+class AeadKeyManagerTest(parameterized.TestCase):
- def setUp(self):
- super(AeadKeyManagerTest, self).setUp()
- self.key_manager_eax = core.Registry.key_manager(
- 'type.googleapis.com/google.crypto.tink.AesEaxKey')
- self.key_manager_gcm = core.Registry.key_manager(
- 'type.googleapis.com/google.crypto.tink.AesGcmKey')
-
- def new_aes_eax_key_template(self, iv_size, key_size):
- key_format = aes_eax_pb2.AesEaxKeyFormat()
- key_format.params.iv_size = iv_size
- key_format.key_size = key_size
- key_template = tink_pb2.KeyTemplate()
- key_template.type_url = ('type.googleapis.com/google.crypto.tink.AesEaxKey')
- key_template.value = key_format.SerializeToString()
- return key_template
-
- def new_aes_gcm_key_template(self, key_size):
- key_format = aes_gcm_pb2.AesGcmKeyFormat()
- key_format.key_size = key_size
- key_template = tink_pb2.KeyTemplate()
- key_template.type_url = ('type.googleapis.com/google.crypto.tink.AesGcmKey')
- key_template.value = key_format.SerializeToString()
- return key_template
-
- def test_primitive_class(self):
- self.assertEqual(self.key_manager_eax.primitive_class(), aead.Aead)
- self.assertEqual(self.key_manager_gcm.primitive_class(), aead.Aead)
-
- def test_key_type(self):
- self.assertEqual(self.key_manager_eax.key_type(),
- 'type.googleapis.com/google.crypto.tink.AesEaxKey')
- self.assertEqual(self.key_manager_gcm.key_type(),
- 'type.googleapis.com/google.crypto.tink.AesGcmKey')
-
- def test_new_key_data(self):
- # AES EAX
- key_template = self.new_aes_eax_key_template(12, 16)
- key_data = self.key_manager_eax.new_key_data(key_template)
- self.assertEqual(key_data.type_url, self.key_manager_eax.key_type())
+ def test_new_key_data_aes_eax(self):
+ key_template = aead.aead_key_templates.create_aes_eax_key_template(
+ key_size=16, iv_size=12)
+ key_manager = core.Registry.key_manager(key_template.type_url)
+ key_data = key_manager.new_key_data(key_template)
+ self.assertEqual(key_data.type_url, key_template.type_url)
self.assertEqual(key_data.key_material_type, tink_pb2.KeyData.SYMMETRIC)
key = aes_eax_pb2.AesEaxKey()
key.ParseFromString(key_data.value)
@@ -78,49 +50,101 @@
self.assertEqual(key.params.iv_size, 12)
self.assertLen(key.key_value, 16)
- # AES GCM
- key_template = self.new_aes_gcm_key_template(16)
- key_data = self.key_manager_gcm.new_key_data(key_template)
- self.assertEqual(key_data.type_url, self.key_manager_gcm.key_type())
+ def test_new_key_data_aes_gcm(self):
+ key_template = aead.aead_key_templates.create_aes_gcm_key_template(
+ key_size=16)
+ key_manager = core.Registry.key_manager(key_template.type_url)
+ key_data = key_manager.new_key_data(key_template)
+ self.assertEqual(key_data.type_url, key_template.type_url)
self.assertEqual(key_data.key_material_type, tink_pb2.KeyData.SYMMETRIC)
key = aes_gcm_pb2.AesGcmKey()
key.ParseFromString(key_data.value)
self.assertEqual(key.version, 0)
self.assertLen(key.key_value, 16)
- def test_invalid_params_throw_exception(self):
- key_template = self.new_aes_eax_key_template(9, 16)
- with self.assertRaisesRegex(core.TinkError, 'Invalid IV size'):
- self.key_manager_eax.new_key_data(key_template)
+ def test_new_key_data_aes_ctr_hmac_aead(self):
+ template = aead.aead_key_templates.create_aes_ctr_hmac_aead_key_template(
+ aes_key_size=16,
+ iv_size=12,
+ hmac_key_size=32,
+ tag_size=16,
+ hash_type=common_pb2.SHA256)
+ key_manager = core.Registry.key_manager(template.type_url)
+ key_data = key_manager.new_key_data(template)
+ self.assertEqual(key_data.type_url, template.type_url)
+ self.assertEqual(key_data.key_material_type, tink_pb2.KeyData.SYMMETRIC)
+ key = aes_ctr_hmac_aead_pb2.AesCtrHmacAeadKey()
+ key.ParseFromString(key_data.value)
+ self.assertEqual(key.version, 0)
+ self.assertEqual(key.aes_ctr_key.version, 0)
+ self.assertLen(key.aes_ctr_key.key_value, 16)
+ self.assertEqual(key.aes_ctr_key.params.iv_size, 12)
+ self.assertEqual(key.hmac_key.version, 0)
+ self.assertLen(key.hmac_key.key_value, 32)
+ self.assertEqual(key.hmac_key.params.tag_size, 16)
+ self.assertEqual(key.hmac_key.params.hash, common_pb2.SHA256)
- key_template = self.new_aes_gcm_key_template(17)
- with self.assertRaisesRegex(core.TinkError,
- 'supported sizes: 16 or 32 bytes'):
- self.key_manager_gcm.new_key_data(key_template)
+ def test_new_key_data_xchacha20_poly1305(self):
+ template = aead.aead_key_templates.XCHACHA20_POLY1305
+ key_manager = core.Registry.key_manager(template.type_url)
+ key_data = key_manager.new_key_data(template)
+ self.assertEqual(key_data.type_url, template.type_url)
+ self.assertEqual(key_data.key_material_type, tink_pb2.KeyData.SYMMETRIC)
+ key = xchacha20_poly1305_pb2.XChaCha20Poly1305Key()
+ key.ParseFromString(key_data.value)
+ self.assertEqual(key.version, 0)
+ self.assertLen(key.key_value, 32)
- def test_encrypt_decrypt(self):
- # AES EAX
- primitive = self.key_manager_eax.primitive(
- self.key_manager_eax.new_key_data(
- self.new_aes_eax_key_template(12, 16)))
+ def test_invalid_params_throw_exception_aes_eax(self):
+ template = aead.aead_key_templates.create_aes_eax_key_template(
+ key_size=16, iv_size=9)
+ with self.assertRaises(tink.TinkError):
+ tink.new_keyset_handle(template)
+
+ def test_invalid_params_throw_exception_aes_gcm(self):
+ template = aead.aead_key_templates.create_aes_gcm_key_template(
+ key_size=17)
+ with self.assertRaises(tink.TinkError):
+ tink.new_keyset_handle(template)
+
+ def test_invalid_params_throw_exception_aes_ctr_hmac_aead(self):
+ template = aead.aead_key_templates.create_aes_ctr_hmac_aead_key_template(
+ aes_key_size=42,
+ iv_size=16,
+ hmac_key_size=32,
+ tag_size=32,
+ hash_type=common_pb2.SHA256)
+ with self.assertRaises(tink.TinkError):
+ tink.new_keyset_handle(template)
+
+ @parameterized.parameters([
+ aead.aead_key_templates.AES128_EAX,
+ aead.aead_key_templates.AES256_EAX,
+ aead.aead_key_templates.AES128_GCM,
+ aead.aead_key_templates.AES256_GCM,
+ aead.aead_key_templates.AES128_CTR_HMAC_SHA256,
+ aead.aead_key_templates.AES256_CTR_HMAC_SHA256,
+ aead.aead_key_templates.XCHACHA20_POLY1305])
+ def test_encrypt_decrypt_success(self, template):
+ keyset_handle = tink.new_keyset_handle(template)
+ primitive = keyset_handle.primitive(aead.Aead)
plaintext = b'plaintext'
associated_data = b'associated_data'
ciphertext = primitive.encrypt(plaintext, associated_data)
self.assertEqual(primitive.decrypt(ciphertext, associated_data), plaintext)
- # AES GCM
- primitive = self.key_manager_gcm.primitive(
- self.key_manager_gcm.new_key_data(self.new_aes_gcm_key_template(16)))
- plaintext = b'plaintext'
- associated_data = b'associated_data'
- ciphertext = primitive.encrypt(plaintext, associated_data)
- self.assertEqual(primitive.decrypt(ciphertext, associated_data), plaintext)
-
- def test_invalid_decrypt_raises_error(self):
- primitive = self.key_manager_eax.primitive(
- self.key_manager_eax.new_key_data(
- self.new_aes_eax_key_template(12, 16)))
- with self.assertRaisesRegex(core.TinkError, 'Ciphertext too short'):
+ @parameterized.parameters([
+ aead.aead_key_templates.AES128_EAX,
+ aead.aead_key_templates.AES256_EAX,
+ aead.aead_key_templates.AES128_GCM,
+ aead.aead_key_templates.AES256_GCM,
+ aead.aead_key_templates.AES128_CTR_HMAC_SHA256,
+ aead.aead_key_templates.AES256_CTR_HMAC_SHA256,
+ aead.aead_key_templates.XCHACHA20_POLY1305])
+ def test_invalid_decrypt_raises_error(self, template):
+ keyset_handle = tink.new_keyset_handle(template)
+ primitive = keyset_handle.primitive(aead.Aead)
+ with self.assertRaises(tink.TinkError):
primitive.decrypt(b'invalid ciphertext', b'ad')
diff --git a/python/tink/aead/_kms_envelope_aead_test.py b/python/tink/aead/_kms_envelope_aead_test.py
index ef6bfa7..2962670 100644
--- a/python/tink/aead/_kms_envelope_aead_test.py
+++ b/python/tink/aead/_kms_envelope_aead_test.py
@@ -82,6 +82,15 @@
with self.assertRaises(core.TinkError):
plaintext = env_aead.decrypt(corrupted_ciphertext, b'some ad')
+ def test_ciphertext_too_short(self):
+ key_template = aead.aead_key_templates.AES256_GCM
+ keyset_handle = tink.new_keyset_handle(key_template)
+ remote_aead = keyset_handle.primitive(aead.Aead)
+ env_aead = aead.KmsEnvelopeAead(key_template, remote_aead)
+
+ with self.assertRaises(core.TinkError):
+ env_aead.decrypt(b'foo', b'some ad')
+
def test_malformed_dek_length(self):
key_template = aead.aead_key_templates.AES256_GCM
keyset_handle = tink.new_keyset_handle(key_template)
diff --git a/python/tink/core/_key_manager.py b/python/tink/core/_key_manager.py
index e3e440c..9ad74f5 100644
--- a/python/tink/core/_key_manager.py
+++ b/python/tink/core/_key_manager.py
@@ -19,8 +19,8 @@
from __future__ import print_function
import abc
-import six
from typing import Any, Generic, Text, Type, TypeVar
+import six
from tink.proto import tink_pb2
from tink.core import _tink_error
@@ -50,7 +50,7 @@
@abc.abstractmethod
def primitive_class(self) -> Type[P]:
"""The class of the primitive it uses. Used for internal management."""
- pass
+ raise NotImplementedError()
@abc.abstractmethod
def primitive(self, key_data: tink_pb2.KeyData) -> P:
@@ -63,12 +63,12 @@
Raises:
tink.TinkError if getting the primitive fails.
"""
- pass
+ raise NotImplementedError()
@abc.abstractmethod
def key_type(self) -> Text:
"""Returns the type_url identifying the key type handled by this manager."""
- pass
+ raise NotImplementedError()
@abc.abstractmethod
def new_key_data(self,
@@ -82,7 +82,7 @@
Raises:
tink.TinkError if the key generation fails.
"""
- pass
+ raise NotImplementedError()
def does_support(self, type_url: Text) -> bool:
return self.key_type() == type_url
@@ -103,7 +103,7 @@
Raises:
tink.TinkError if the key generation fails.
"""
- pass
+ raise NotImplementedError()
class KeyManagerCcToPyWrapper(KeyManager[P]):
diff --git a/python/tink/core/_registry_test.py b/python/tink/core/_registry_test.py
index 1699de5..1ac8e3e 100644
--- a/python/tink/core/_registry_test.py
+++ b/python/tink/core/_registry_test.py
@@ -43,6 +43,12 @@
return tink_pb2.KeyData(type_url=key_template.type_url)
+class UnsupportedKeyManager(DummyKeyManager):
+
+ def does_support(self, type_url):
+ return False
+
+
class DummyPrivateKeyManager(core.PrivateKeyManager):
def __init__(self, type_url):
@@ -120,6 +126,10 @@
self.reg.register_key_manager(DummyKeyManager('dummy_type_url', aead.Aead))
self.reg.register_key_manager(DummyKeyManager('dummy_type_url', aead.Aead))
+ def test_register_unsupported_key_manager_fails(self):
+ with self.assertRaises(core.TinkError):
+ self.reg.register_key_manager(UnsupportedKeyManager('unsupported'))
+
def test_key_manager_replace_fails(self):
self.reg.register_key_manager(DummyKeyManager('dummy_type_url', aead.Aead))
# Replacing the primitive_class for a type_url not allowed.
diff --git a/python/tink/integration/awskms/BUILD.bazel b/python/tink/integration/awskms/BUILD.bazel
index 8537e63..bb0cf92 100644
--- a/python/tink/integration/awskms/BUILD.bazel
+++ b/python/tink/integration/awskms/BUILD.bazel
@@ -33,6 +33,7 @@
],
deps = [
":awskms",
+ "//tink/testing:helper",
requirement("absl-py"),
],
)
@@ -46,6 +47,7 @@
],
deps = [
":awskms",
+ "//tink/testing:helper",
requirement("absl-py"),
],
)
diff --git a/python/tink/integration/awskms/_aws_kms_aead_test.py b/python/tink/integration/awskms/_aws_kms_aead_test.py
index b08104d..9223aeb 100644
--- a/python/tink/integration/awskms/_aws_kms_aead_test.py
+++ b/python/tink/integration/awskms/_aws_kms_aead_test.py
@@ -22,11 +22,12 @@
from tink import core
from tink.integration import awskms
+from tink.testing import helper
-CREDENTIAL_PATH = os.path.join(os.environ['TEST_SRCDIR'],
- 'tink_base/testdata/aws_credentials_cc.txt')
-BAD_CREDENTIALS_PATH = os.path.join(
- os.environ['TEST_SRCDIR'], 'tink_base/testdata/bad_aws_credentials_cc.txt')
+CREDENTIAL_PATH = os.path.join(helper.get_tink_src_path(),
+ 'testdata/aws_credentials_cc.txt')
+BAD_CREDENTIALS_PATH = os.path.join(helper.get_tink_src_path(),
+ 'testdata/bad_aws_credentials_cc.txt')
KEY_URI = 'aws-kms://arn:aws:kms:us-east-2:235739564943:key/3ee50705-5a82-4f5b-9753-05c4f473922f'
BAD_KEY_URI = 'gcp-kms://projects/tink-test-infrastructure/locations/global/keyRings/unit-and-integration-testing/cryptoKeys/aead-key'
diff --git a/python/tink/integration/awskms/_aws_kms_client_test.py b/python/tink/integration/awskms/_aws_kms_client_test.py
index 6c8f01b..0f7c150 100644
--- a/python/tink/integration/awskms/_aws_kms_client_test.py
+++ b/python/tink/integration/awskms/_aws_kms_client_test.py
@@ -22,9 +22,10 @@
from tink import core
from tink.integration import awskms
+from tink.testing import helper
-CREDENTIAL_PATH = os.path.join(os.environ['TEST_SRCDIR'],
- 'tink_base/testdata/aws_credentials_cc.txt')
+CREDENTIAL_PATH = os.path.join(helper.get_tink_src_path(),
+ 'testdata/aws_credentials_cc.txt')
KEY_URI = 'aws-kms://arn:aws:kms:us-east-2:235739564943:key/3ee50705-5a82-4f5b-9753-05c4f473922f'
BAD_KEY_URI = 'gcp-kms://projects/tink-test-infrastructure/locations/global/keyRings/unit-and-integration-testing/cryptoKeys/aead-key'
diff --git a/python/tink/integration/gcpkms/BUILD.bazel b/python/tink/integration/gcpkms/BUILD.bazel
index 2ac876a..b1e5172 100644
--- a/python/tink/integration/gcpkms/BUILD.bazel
+++ b/python/tink/integration/gcpkms/BUILD.bazel
@@ -33,6 +33,7 @@
],
deps = [
":gcpkms",
+ "//tink/testing:helper",
requirement("absl-py"),
]
)
@@ -47,6 +48,7 @@
],
deps = [
":gcpkms",
+ "//tink/testing:helper",
requirement("absl-py"),
]
)
diff --git a/python/tink/integration/gcpkms/_gcp_kms_aead_test.py b/python/tink/integration/gcpkms/_gcp_kms_aead_test.py
index bc52fad..bdfbe0a 100644
--- a/python/tink/integration/gcpkms/_gcp_kms_aead_test.py
+++ b/python/tink/integration/gcpkms/_gcp_kms_aead_test.py
@@ -23,15 +23,18 @@
from tink import core
from tink.integration import gcpkms
+from tink.testing import helper
-CREDENTIAL_PATH = os.path.join(os.environ['TEST_SRCDIR'],
- 'tink_base/testdata/credential.json')
+CREDENTIAL_PATH = os.path.join(helper.get_tink_src_path(),
+ 'testdata/credential.json')
KEY_URI = 'gcp-kms://projects/tink-test-infrastructure/locations/global/keyRings/unit-and-integration-testing/cryptoKeys/aead-key'
+LOCAL_KEY_URI = 'gcp-kms://projects/tink-test-infrastructure/locations/europe-west1/keyRings/unit-and-integration-test/cryptoKeys/aead-key'
BAD_KEY_URI = 'aws-kms://arn:aws:kms:us-east-2:235739564943:key/3ee50705-5a82-4f5b-9753-05c4f473922f'
-# Set root certificates for gRPC
-os.environ['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = os.path.join(
- os.environ['TEST_SRCDIR'], 'google_root_pem/file/downloaded')
+if 'TEST_SRCDIR' in os.environ:
+ # Set root certificates for gRPC in Bazel Test which are needed on MacOS
+ os.environ['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = os.path.join(
+ os.environ['TEST_SRCDIR'], 'google_root_pem/file/downloaded')
class GcpKmsAeadTest(absltest.TestCase):
@@ -49,6 +52,19 @@
ciphertext = aead.encrypt(plaintext, associated_data)
self.assertEqual(plaintext, aead.decrypt(ciphertext, associated_data))
+ def test_encrypt_decrypt_localized_uri(self):
+ gcp_client = gcpkms.GcpKmsClient(LOCAL_KEY_URI, CREDENTIAL_PATH)
+ aead = gcp_client.get_aead(LOCAL_KEY_URI)
+
+ plaintext = b'helloworld'
+ ciphertext = aead.encrypt(plaintext, b'')
+ self.assertEqual(plaintext, aead.decrypt(ciphertext, b''))
+
+ plaintext = b'hello'
+ associated_data = b'world'
+ ciphertext = aead.encrypt(plaintext, associated_data)
+ self.assertEqual(plaintext, aead.decrypt(ciphertext, associated_data))
+
def test_encrypt_with_bad_uri(self):
with self.assertRaises(core.TinkError):
gcp_client = gcpkms.GcpKmsClient(KEY_URI, CREDENTIAL_PATH)
diff --git a/python/tink/integration/gcpkms/_gcp_kms_client_test.py b/python/tink/integration/gcpkms/_gcp_kms_client_test.py
index db7741c..41bc932 100644
--- a/python/tink/integration/gcpkms/_gcp_kms_client_test.py
+++ b/python/tink/integration/gcpkms/_gcp_kms_client_test.py
@@ -22,9 +22,11 @@
from absl.testing import absltest
from tink.integration import gcpkms
+from tink.testing import helper
-CREDENTIAL_PATH = os.path.join(os.environ['TEST_SRCDIR'],
- 'tink_base/testdata/credential.json')
+
+CREDENTIAL_PATH = os.path.join(helper.get_tink_src_path(),
+ 'testdata/credential.json')
class GcpKmsClientTest(absltest.TestCase):
diff --git a/python/tink/proto/aes_cmac.proto b/python/tink/proto/aes_cmac.proto
index ee150c4..b214834 100644
--- a/python/tink/proto/aes_cmac.proto
+++ b/python/tink/proto/aes_cmac.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_cmac_go_proto";
message AesCmacParams {
diff --git a/python/tink/proto/aes_cmac_prf.proto b/python/tink/proto/aes_cmac_prf.proto
index de8f32a..cd75015 100644
--- a/python/tink/proto/aes_cmac_prf.proto
+++ b/python/tink/proto/aes_cmac_prf.proto
@@ -18,7 +18,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_cmac_prf_go_proto";
// key_type: type.googleapis.com/google.crypto.tink.AesCmacPrfKey
diff --git a/python/tink/proto/aes_ctr.proto b/python/tink/proto/aes_ctr.proto
index 27c9d4e..ecdb256 100644
--- a/python/tink/proto/aes_ctr.proto
+++ b/python/tink/proto/aes_ctr.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_go_proto";
message AesCtrParams {
diff --git a/python/tink/proto/aes_ctr_hmac_aead.proto b/python/tink/proto/aes_ctr_hmac_aead.proto
index 9af2b7f..bde8649 100644
--- a/python/tink/proto/aes_ctr_hmac_aead.proto
+++ b/python/tink/proto/aes_ctr_hmac_aead.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_hmac_aead_go_proto";
message AesCtrHmacAeadKeyFormat {
diff --git a/python/tink/proto/aes_ctr_hmac_streaming.proto b/python/tink/proto/aes_ctr_hmac_streaming.proto
index 4d60d5e..3963c27 100644
--- a/python/tink/proto/aes_ctr_hmac_streaming.proto
+++ b/python/tink/proto/aes_ctr_hmac_streaming.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_ctr_hmac_streaming_go_proto";
message AesCtrHmacStreamingParams {
diff --git a/python/tink/proto/aes_eax.proto b/python/tink/proto/aes_eax.proto
index d84ad2a..c673306 100644
--- a/python/tink/proto/aes_eax.proto
+++ b/python/tink/proto/aes_eax.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_eax_go_proto";
// only allowing tag size in bytes = 16
diff --git a/python/tink/proto/aes_gcm.proto b/python/tink/proto/aes_gcm.proto
index 2a0c584..ca1483f 100644
--- a/python/tink/proto/aes_gcm.proto
+++ b/python/tink/proto/aes_gcm.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_go_proto";
// only allowing IV size in bytes = 12 and tag size in bytes = 16
diff --git a/python/tink/proto/aes_gcm_hkdf_streaming.proto b/python/tink/proto/aes_gcm_hkdf_streaming.proto
index b339bea..15985f0 100644
--- a/python/tink/proto/aes_gcm_hkdf_streaming.proto
+++ b/python/tink/proto/aes_gcm_hkdf_streaming.proto
@@ -19,11 +19,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "tink/proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_hkdf_streaming_go_proto";
message AesGcmHkdfStreamingParams {
diff --git a/python/tink/proto/aes_gcm_siv.proto b/python/tink/proto/aes_gcm_siv.proto
index 2824a54..d97d191 100644
--- a/python/tink/proto/aes_gcm_siv.proto
+++ b/python/tink/proto/aes_gcm_siv.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_gcm_siv_go_proto";
// The only allowed IV size is 12 bytes and tag size is 16 bytes.
diff --git a/python/tink/proto/aes_siv.proto b/python/tink/proto/aes_siv.proto
index 6442587..ae4bdfe 100644
--- a/python/tink/proto/aes_siv.proto
+++ b/python/tink/proto/aes_siv.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/aes_siv_go_proto";
message AesSivKeyFormat {
diff --git a/python/tink/proto/chacha20_poly1305.proto b/python/tink/proto/chacha20_poly1305.proto
index 57ec1ca..2cd6ead 100644
--- a/python/tink/proto/chacha20_poly1305.proto
+++ b/python/tink/proto/chacha20_poly1305.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/chacha20_poly1305_go_proto";
message ChaCha20Poly1305KeyFormat {}
diff --git a/python/tink/proto/common.proto b/python/tink/proto/common.proto
index 2c640a9..d5862d5 100644
--- a/python/tink/proto/common.proto
+++ b/python/tink/proto/common.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/common_go_proto";
enum EllipticCurveType {
diff --git a/python/tink/proto/config.proto b/python/tink/proto/config.proto
index 4017053..ebbd742 100644
--- a/python/tink/proto/config.proto
+++ b/python/tink/proto/config.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/config_go_proto";
// An entry that describes a key type to be used with Tink library,
@@ -31,12 +30,12 @@
// KeyTypeEntry is no longer supported.
option deprecated = true;
- string primitive_name = 1; // E.g. “Aead”, “Mac”, ... (case-insensitive)
- string type_url = 2; // Name of the key type.
+ string primitive_name = 1; // E.g. “Aead”, “Mac”, ... (case-insensitive)
+ string type_url = 2; // Name of the key type.
uint32 key_manager_version = 3; // Minimum required version of key manager.
bool new_key_allowed = 4; // Can the key manager create new keys?
- string catalogue_name = 5; // Catalogue to be queried for key manager,
- // e.g. "Tink", "Custom", ... (case-insensitive)
+ string catalogue_name = 5; // Catalogue to be queried for key manager,
+ // e.g. "Tink", "Custom", ... (case-insensitive)
}
// A complete configuration of Tink library: a list of key types
diff --git a/python/tink/proto/ecdsa.proto b/python/tink/proto/ecdsa.proto
index df80d9f..043a3d8 100644
--- a/python/tink/proto/ecdsa.proto
+++ b/python/tink/proto/ecdsa.proto
@@ -18,18 +18,18 @@
syntax = "proto3";
package google.crypto.tink;
+
import "tink/proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ecdsa_go_proto";
enum EcdsaSignatureEncoding {
UNKNOWN_ENCODING = 0;
- // The signature's format is r || s, where r and s are zero-padded and have the same size in
- // bytes as the order of the curve. For example, for NIST P-256 curve, r and s are zero-padded to
- // 32 bytes.
+ // The signature's format is r || s, where r and s are zero-padded and have
+ // the same size in bytes as the order of the curve. For example, for NIST
+ // P-256 curve, r and s are zero-padded to 32 bytes.
IEEE_P1363 = 1;
// The signature is encoded using ASN.1
// (https://tools.ietf.org/html/rfc5480#appendix-A):
diff --git a/python/tink/proto/ecies_aead_hkdf.proto b/python/tink/proto/ecies_aead_hkdf.proto
index 7572f69..6cf6b34 100644
--- a/python/tink/proto/ecies_aead_hkdf.proto
+++ b/python/tink/proto/ecies_aead_hkdf.proto
@@ -18,25 +18,29 @@
syntax = "proto3";
package google.crypto.tink;
+
import "tink/proto/common.proto";
import "tink/proto/tink.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ecies_aead_hkdf_go_proto";
// Protos for keys for ECIES with HKDF and AEAD encryption.
//
// These definitions follow loosely ECIES ISO 18033-2 standard
-// (Elliptic Curve Integrated Encryption Scheme, see http://www.shoup.net/iso/std6.pdf),
-// with but with some differences:
-// * use of HKDF key derivation function (instead of KDF1 and KDF2) enabling the use
-// of optional parameters to the key derivation function, which strenghten the overall
-// security and allow for binding the key material to application-specific information
-// (cf. RFC 5869, https://tools.ietf.org/html/rfc5869)
-// * use of modern AEAD schemes rather than "manual composition" of symmetric encryption
-// with message authentication codes (as in DEM1, DEM2, and DEM3 schemes of ISO 18033-2)
+// (Elliptic Curve Integrated Encryption Scheme, see
+// http://www.shoup.net/iso/std6.pdf), with but with some differences:
+// * use of HKDF key derivation function (instead of KDF1 and KDF2) enabling
+// the use
+// of optional parameters to the key derivation function, which strenghten
+// the overall security and allow for binding the key material to
+// application-specific information (cf. RFC 5869,
+// https://tools.ietf.org/html/rfc5869)
+// * use of modern AEAD schemes rather than "manual composition" of symmetric
+// encryption
+// with message authentication codes (as in DEM1, DEM2, and DEM3 schemes of
+// ISO 18033-2)
//
// ECIES-keys represent HybridEncryption resp. HybridDecryption primitives.
@@ -55,7 +59,8 @@
// Parameters of AEAD DEM (Data Encapsulation Mechanism).
message EciesAeadDemParams {
// Required.
- KeyTemplate aead_dem = 2; // Contains e.g. AesCtrHmacAeadKeyFormat or AesGcmKeyFormat.
+ KeyTemplate aead_dem =
+ 2; // Contains e.g. AesCtrHmacAeadKeyFormat or AesGcmKeyFormat.
}
message EciesAeadHkdfParams {
@@ -81,8 +86,8 @@
EciesAeadHkdfParams params = 2;
// Affine coordinates of the public key in bigendian representation.
- // The public key is a point (x, y) on the curve defined by params.kem_params.curve.
- // Required.
+ // The public key is a point (x, y) on the curve defined by
+ // params.kem_params.curve. Required.
bytes x = 3;
// Required.
bytes y = 4;
diff --git a/python/tink/proto/ed25519.proto b/python/tink/proto/ed25519.proto
index 19b8789..93a5d7d 100644
--- a/python/tink/proto/ed25519.proto
+++ b/python/tink/proto/ed25519.proto
@@ -23,7 +23,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/ed25519_go_proto";
message Ed25519KeyFormat {}
diff --git a/python/tink/proto/empty.proto b/python/tink/proto/empty.proto
index 757b6e2..33831a9 100644
--- a/python/tink/proto/empty.proto
+++ b/python/tink/proto/empty.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/empty_go_proto";
message Empty {}
diff --git a/python/tink/proto/hkdf_prf.proto b/python/tink/proto/hkdf_prf.proto
index 7bd31be..394f7b3 100644
--- a/python/tink/proto/hkdf_prf.proto
+++ b/python/tink/proto/hkdf_prf.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hkdf_prf_proto";
message HkdfPrfParams {
diff --git a/python/tink/proto/hmac.proto b/python/tink/proto/hmac.proto
index 8974f64..9395845 100644
--- a/python/tink/proto/hmac.proto
+++ b/python/tink/proto/hmac.proto
@@ -22,11 +22,10 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hmac_go_proto";
message HmacParams {
- HashType hash = 1; // HashType is an enum.
+ HashType hash = 1; // HashType is an enum.
uint32 tag_size = 2;
}
diff --git a/python/tink/proto/hmac_prf.proto b/python/tink/proto/hmac_prf.proto
index 5f2c4cd..770b4f9 100644
--- a/python/tink/proto/hmac_prf.proto
+++ b/python/tink/proto/hmac_prf.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/hmac_prf_go_proto";
message HmacPrfParams {
diff --git a/python/tink/proto/jws_hmac.proto b/python/tink/proto/jws_hmac.proto
new file mode 100644
index 0000000..2c4a698
--- /dev/null
+++ b/python/tink/proto/jws_hmac.proto
@@ -0,0 +1,36 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+syntax = "proto3";
+
+package google.crypto.tink;
+
+import "tink/proto/common.proto";
+
+option java_package = "com.google.crypto.tink.proto";
+option java_multiple_files = true;
+option go_package = "github.com/google/tink/proto/jws_hmac_go_proto";
+
+// key_type: type.googleapis.com/google.crypto.tink.JwsHmacKey
+message JwsHmacKey {
+ uint32 version = 1;
+ HashType hash_type = 2;
+ bytes key_value = 3;
+}
+
+message JwsHmacKeyFormat {
+ uint32 version = 1;
+ HashType hash_type = 2;
+ uint32 key_size = 3;
+}
diff --git a/python/tink/proto/kms_aead.proto b/python/tink/proto/kms_aead.proto
index b7e077c..e818788 100644
--- a/python/tink/proto/kms_aead.proto
+++ b/python/tink/proto/kms_aead.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/kms_aead_go_proto";
message KmsAeadKeyFormat {
diff --git a/python/tink/proto/kms_envelope.proto b/python/tink/proto/kms_envelope.proto
index 1752b5b..17888d9 100644
--- a/python/tink/proto/kms_envelope.proto
+++ b/python/tink/proto/kms_envelope.proto
@@ -22,7 +22,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/kms_envelope_go_proto";
message KmsEnvelopeAeadKeyFormat {
diff --git a/python/tink/proto/prf_based_deriver.proto b/python/tink/proto/prf_based_deriver.proto
index 92fe552..110c92e 100644
--- a/python/tink/proto/prf_based_deriver.proto
+++ b/python/tink/proto/prf_based_deriver.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/prf_based_deriver_go_proto";
message PrfBasedDeriverParams {
diff --git a/python/tink/proto/rsa_ssa_pkcs1.proto b/python/tink/proto/rsa_ssa_pkcs1.proto
index 3ff3394..fd5fd4e 100644
--- a/python/tink/proto/rsa_ssa_pkcs1.proto
+++ b/python/tink/proto/rsa_ssa_pkcs1.proto
@@ -19,11 +19,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "tink/proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/rsa_ssa_pkcs1_go_proto";
message RsaSsaPkcs1Params {
diff --git a/python/tink/proto/rsa_ssa_pss.proto b/python/tink/proto/rsa_ssa_pss.proto
index e819f23..a4817c0 100644
--- a/python/tink/proto/rsa_ssa_pss.proto
+++ b/python/tink/proto/rsa_ssa_pss.proto
@@ -20,11 +20,11 @@
syntax = "proto3";
package google.crypto.tink;
+
import "tink/proto/common.proto";
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/rsa_ssa_pss_go_proto";
message RsaSsaPssParams {
diff --git a/python/tink/proto/testing/testing_api.proto b/python/tink/proto/testing/testing_api.proto
new file mode 100644
index 0000000..2c0dde4
--- /dev/null
+++ b/python/tink/proto/testing/testing_api.proto
@@ -0,0 +1,288 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto3";
+
+package tink_testing_api;
+
+option java_package = "com.google.crypto.tink.proto.testing";
+option java_multiple_files = true;
+
+// Service providing metadata about the server.
+service Metadata {
+ // Returns some server information. A test may use this information to verify
+ // that it is talking to the right server.
+ rpc GetServerInfo(ServerInfoRequest) returns (ServerInfoResponse) {}
+}
+
+message ServerInfoRequest {}
+
+message ServerInfoResponse {
+ string tink_version = 1; // For example '1.4'
+ string language = 2; // For example 'cc', 'java', 'go' or 'python'.
+}
+
+// Service for Keyset operations.
+service Keyset {
+ // Generates a new keyset from a template.
+ rpc Generate(KeysetGenerateRequest) returns (KeysetGenerateResponse) {}
+ // Generates a public-key keyset from a private-key keyset.
+ rpc Public(KeysetPublicRequest) returns (KeysetPublicResponse) {}
+ // Converts a Keyset from Binary to Json Format
+ rpc ToJson(KeysetToJsonRequest) returns (KeysetToJsonResponse) {}
+ // Converts a Keyset from Json to Binary Format
+ rpc FromJson(KeysetFromJsonRequest) returns (KeysetFromJsonResponse) {}
+}
+
+message KeysetGenerateRequest {
+ bytes template = 1; // serialized google.crypto.tink.KeyTemplate.
+}
+
+message KeysetGenerateResponse {
+ oneof result {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+message KeysetPublicRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+}
+
+message KeysetPublicResponse {
+ oneof result {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+message KeysetToJsonRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+}
+
+message KeysetToJsonResponse {
+ oneof result {
+ string json_keyset = 1;
+ string err = 2;
+ }
+}
+
+message KeysetFromJsonRequest {
+ string json_keyset = 1;
+}
+
+message KeysetFromJsonResponse {
+ oneof result {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ string err = 2;
+ }
+}
+
+// Service for AEAD encryption and decryption
+service Aead {
+ // Encrypts a plaintext with the provided keyset
+ rpc Encrypt(AeadEncryptRequest) returns (AeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc Decrypt(AeadDecryptRequest) returns (AeadDecryptResponse) {}
+}
+
+message AeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message AeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message AeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message AeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service for Deterministic AEAD encryption and decryption
+service DeterministicAead {
+ // Encrypts a plaintext with the provided keyset
+ rpc EncryptDeterministically(DeterministicAeadEncryptRequest)
+ returns (DeterministicAeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc DecryptDeterministically(DeterministicAeadDecryptRequest)
+ returns (DeterministicAeadDecryptResponse) {
+ }
+}
+
+message DeterministicAeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message DeterministicAeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message DeterministicAeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message DeterministicAeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service for Streaming AEAD encryption and decryption
+service StreamingAead {
+ // Encrypts a plaintext with the provided keyset
+ rpc Encrypt(StreamingAeadEncryptRequest)
+ returns (StreamingAeadEncryptResponse) {}
+ // Decrypts a ciphertext with the provided keyset
+ rpc Decrypt(StreamingAeadDecryptRequest)
+ returns (StreamingAeadDecryptResponse) {}
+}
+
+message StreamingAeadEncryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes associated_data = 3;
+}
+
+message StreamingAeadEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message StreamingAeadDecryptRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes associated_data = 3;
+}
+
+message StreamingAeadDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service to compute and verify MACs
+service Mac {
+ // Computes a MAC for given data
+ rpc ComputeMac(ComputeMacRequest) returns (ComputeMacResponse) {}
+ // Verifies the validity of the MAC value, no error means success
+ rpc VerifyMac(VerifyMacRequest) returns (VerifyMacResponse) {}
+}
+
+message ComputeMacRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes data = 2;
+}
+
+message ComputeMacResponse {
+ oneof result {
+ bytes mac_value = 1;
+ string err = 2;
+ }
+}
+
+message VerifyMacRequest {
+ bytes keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes mac_value = 2;
+ bytes data = 3;
+}
+
+message VerifyMacResponse {
+ string err = 1;
+}
+
+// Service to hybrid encrypt and decrypt
+service Hybrid {
+ // Encrypts plaintext binding context_info to the resulting ciphertext
+ rpc Encrypt(HybridEncryptRequest) returns (HybridEncryptResponse) {}
+ // Decrypts ciphertext verifying the integrity of context_info
+ rpc Decrypt(HybridDecryptRequest) returns (HybridDecryptResponse) {}
+}
+
+message HybridEncryptRequest {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes plaintext = 2;
+ bytes context_info = 3;
+}
+
+message HybridEncryptResponse {
+ oneof result {
+ bytes ciphertext = 1;
+ string err = 2;
+ }
+}
+
+message HybridDecryptRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes ciphertext = 2;
+ bytes context_info = 3;
+}
+
+message HybridDecryptResponse {
+ oneof result {
+ bytes plaintext = 1;
+ string err = 2;
+ }
+}
+
+// Service to sign and verify signatures.
+service Signature {
+ // Computes the signature for data
+ rpc Sign(SignatureSignRequest) returns (SignatureSignResponse) {}
+ // Verifies that signature is a digital signature for data
+ rpc Verify(SignatureVerifyRequest) returns (SignatureVerifyResponse) {}
+}
+
+message SignatureSignRequest {
+ bytes private_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes data = 2;
+}
+
+message SignatureSignResponse {
+ oneof result {
+ bytes signature = 1;
+ string err = 2;
+ }
+}
+
+message SignatureVerifyRequest {
+ bytes public_keyset = 1; // serialized google.crypto.tink.Keyset.
+ bytes signature = 2;
+ bytes data = 3;
+}
+
+message SignatureVerifyResponse {
+ string err = 1;
+}
diff --git a/python/tink/proto/tink.proto b/python/tink/proto/tink.proto
index cfc125f..743906d 100644
--- a/python/tink/proto/tink.proto
+++ b/python/tink/proto/tink.proto
@@ -21,7 +21,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/tink_go_proto";
// Each instantiation of a Tink primitive is identified by type_url,
@@ -54,7 +53,7 @@
string type_url = 1; // in format type.googleapis.com/packagename.messagename
// Optional.
// If missing, it means the key type doesn't require a *KeyFormat proto.
- bytes value = 2; // contains specific serialized *KeyFormat proto
+ bytes value = 2; // contains specific serialized *KeyFormat proto
// Optional.
// If missing, uses OutputPrefixType.TINK.
OutputPrefixType output_prefix_type = 3;
@@ -112,13 +111,13 @@
// Required.
string type_url = 1; // In format type.googleapis.com/packagename.messagename
// Required.
- bytes value = 2; // contains specific serialized *Key proto
+ bytes value = 2; // contains specific serialized *Key proto
enum KeyMaterialType {
UNKNOWN_KEYMATERIAL = 0;
SYMMETRIC = 1;
ASYMMETRIC_PRIVATE = 2;
ASYMMETRIC_PUBLIC = 3;
- REMOTE = 4; // points to a remote key, i.e., in a KMS.
+ REMOTE = 4; // points to a remote key, i.e., in a KMS.
}
// Required.
KeyMaterialType key_material_type = 3;
@@ -130,7 +129,6 @@
// Any given keyset (and any given key) can be used for one primitive only.
message Keyset {
message Key {
-
// Contains the actual, instantiation specific key proto.
// By convention, each key proto contains a version field.
KeyData key_data = 1;
diff --git a/python/tink/proto/xchacha20_poly1305.proto b/python/tink/proto/xchacha20_poly1305.proto
index 353814c..29d3938 100644
--- a/python/tink/proto/xchacha20_poly1305.proto
+++ b/python/tink/proto/xchacha20_poly1305.proto
@@ -20,7 +20,6 @@
option java_package = "com.google.crypto.tink.proto";
option java_multiple_files = true;
-option objc_class_prefix = "TINKPB";
option go_package = "github.com/google/tink/proto/xchacha20_poly1305_go_proto";
message XChaCha20Poly1305KeyFormat {}
diff --git a/python/tink/streaming_aead/BUILD.bazel b/python/tink/streaming_aead/BUILD.bazel
index dbbc344..43de0b5 100644
--- a/python/tink/streaming_aead/BUILD.bazel
+++ b/python/tink/streaming_aead/BUILD.bazel
@@ -9,6 +9,7 @@
name = "streaming_aead",
srcs = ["__init__.py"],
srcs_version = "PY3",
+ visibility = ["//visibility:public"],
deps = [
":_decrypting_stream",
":_encrypting_stream",
diff --git a/python/tink/streaming_aead/__init__.py b/python/tink/streaming_aead/__init__.py
index a7d2e3a..995f7ae 100644
--- a/python/tink/streaming_aead/__init__.py
+++ b/python/tink/streaming_aead/__init__.py
@@ -27,4 +27,4 @@
DecryptingStream = _decrypting_stream.DecryptingStream
EncryptingStream = _encrypting_stream.EncryptingStream
key_manager_from_cc_registry = _streaming_aead_key_manager.from_cc_registry
-
+register = _streaming_aead_key_manager.register
diff --git a/python/tink/streaming_aead/_streaming_aead_key_manager.py b/python/tink/streaming_aead/_streaming_aead_key_manager.py
index 9314edd..9daf5ec 100644
--- a/python/tink/streaming_aead/_streaming_aead_key_manager.py
+++ b/python/tink/streaming_aead/_streaming_aead_key_manager.py
@@ -54,3 +54,17 @@
return core.KeyManagerCcToPyWrapper(
tink_bindings.StreamingAeadKeyManager.from_cc_registry(type_url),
_streaming_aead.StreamingAead, _StreamingAeadCcToPyWrapper)
+
+
+def register() -> None:
+ """Registers all AEAD key managers and AEAD wrapper in the Registry."""
+ tink_bindings.register()
+ for ident in (
+ 'AesCtrHmacStreamingKey',
+ 'AesGcmHkdfStreamingKey',
+ ):
+ type_url = 'type.googleapis.com/google.crypto.tink.{}'.format(ident)
+ key_manager = core.KeyManagerCcToPyWrapper(
+ tink_bindings.StreamingAeadKeyManager.from_cc_registry(type_url),
+ _streaming_aead.StreamingAead, _StreamingAeadCcToPyWrapper)
+ core.Registry.register_key_manager(key_manager, new_key_allowed=True)
diff --git a/python/tink/testing/__init__.py b/python/tink/testing/__init__.py
new file mode 100644
index 0000000..824dd6c
--- /dev/null
+++ b/python/tink/testing/__init__.py
@@ -0,0 +1,11 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/python/tink/testing/helper.py b/python/tink/testing/helper.py
index e13691d..dd28580 100644
--- a/python/tink/testing/helper.py
+++ b/python/tink/testing/helper.py
@@ -19,6 +19,7 @@
# Placeholder for import for type annotations
from __future__ import print_function
+import os
from typing import Text
from tink.proto import tink_pb2
@@ -30,6 +31,24 @@
from tink import signature as pk_signature
+def get_tink_src_path():
+ """Returns the path to the Tink root directory used for the test enviroment.
+
+ The path must be set in the TINK_SRC_PATH enviroment variable. If Bazel
+ is used the path is derived from the Bazel enviroment variables.
+ """
+ if 'TINK_SRC_PATH' in os.environ:
+ return os.environ['TINK_SRC_PATH']
+ elif 'TEST_SRCDIR' in os.environ:
+ # Bazel enviroment
+ return os.path.join(os.environ['TEST_SRCDIR'], 'tink_base')
+ else:
+ raise ValueError(
+ 'Could not find path to Tink root directory. Make sure that '
+ 'TINK_SRC_PATH is set.'
+ )
+
+
def fake_key(value: bytes = b'fakevalue',
type_url: Text = 'fakeurl',
key_material_type: tink_pb2.KeyData.KeyMaterialType = tink_pb2
diff --git a/python/tink/util/__init__.py b/python/tink/util/__init__.py
new file mode 100644
index 0000000..824dd6c
--- /dev/null
+++ b/python/tink/util/__init__.py
@@ -0,0 +1,11 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/python/tink/util/file_object_adapter_test.py b/python/tink/util/file_object_adapter_test.py
index 41ab5e5..4c10815 100644
--- a/python/tink/util/file_object_adapter_test.py
+++ b/python/tink/util/file_object_adapter_test.py
@@ -106,6 +106,12 @@
self.assertEqual(adapter.read(0), b'')
+ def test_read_negative_size_fails(self):
+ file_object = io.BytesIO(b'something')
+ adapter = file_object_adapter.FileObjectAdapter(file_object)
+ with self.assertRaises(ValueError):
+ adapter.read(-1)
+
def test_read_raises_blocking_error(self):
file_object = mock.Mock()
file_object.read = mock.Mock(side_effect=io.BlockingIOError(None, None))
diff --git a/python/tools/distribution/README.md b/python/tools/distribution/README.md
new file mode 100644
index 0000000..e199c14
--- /dev/null
+++ b/python/tools/distribution/README.md
@@ -0,0 +1,56 @@
+# Overview
+
+This folder contains scripts to build binary and source wheels of the Tink
+Python package.
+
+## Building the release
+
+In order to generate a release run `./tools/distribution/create_release.sh` from
+the `python/` folder. Note that this requires [https://www.docker.com](Docker)
+to be installed, as it makes use of the
+[https://github.com/pypa/manylinux](pypa images) to build
+[https://www.python.org/dev/peps/pep-0599/](PEP 599) conform wheels.
+
+This will carry out the following three steps:
+
+* Create binary wheels in a Docker container for Linux.
+* Create a source distribution of the Python package.
+* Run automatic tests against the packages created.
+
+The resulting packages of this process will be stored in `python/release` and
+can be distributed. The binary wheels can be installed on Linux without
+Bazel/protoc being available. Currently this supports building binary wheels
+for:
+
+* manylinux2014_x86_64: Python 3.7, 3.8
+
+The binary wheels are tested inside a Docker container with the corresponding
+Python versions.
+
+The source distribution still needs to compile the C++ bindings, which requires
+Bazel, protoc and the Tink repository to be available. The path to the Tink
+repository can be set with `TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH`. The
+source distribution is tested on the machine which the script is run.
+
+## Publishing the release
+
+The output generated in the previous step can directly be used for upload to
+PyPI. It is recommended to first upload it to the
+[https://test.pypi.org](test repository):
+
+```
+python3 -m twine upload --repository testpypi release/*
+```
+
+The package can then be installed using
+
+```
+pip3 install -i https://test.pypi.org/simple/ tink
+```
+
+In order to upload it to the PyPI repository run
+
+```
+python3 -m twine upload release/*
+```
+
diff --git a/python/tools/distribution/build_linux_binary_wheels.sh b/python/tools/distribution/build_linux_binary_wheels.sh
new file mode 100755
index 0000000..997abf9
--- /dev/null
+++ b/python/tools/distribution/build_linux_binary_wheels.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# This script builds binary wheels of Tink for Linux based on PEP 599. It
+# should be run inside a manylinux2014 Docker container to have the correct
+# environment setup.
+
+set -euo pipefail
+
+# Get dependencies which are needed for building Tink
+# Install Bazel which is needed for building C++ extensions
+BAZEL_VERSION='3.1.0'
+curl -OL https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh
+chmod +x bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh
+./bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh
+
+# Install Protoc which is needed for compiling the protos
+PROTOC_ZIP='protoc-3.11.4-linux-x86_64.zip'
+curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/${PROTOC_ZIP}
+unzip -o "${PROTOC_ZIP}" -d /usr/local bin/protoc
+
+# Setup required for Tink
+export TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH=/tmp/tink
+
+# Build wheel for Python 3.7
+(
+ # Set Path to Python3.7
+ export PATH=$PATH:/opt/python/cp37-cp37m/bin
+
+ # Create binary wheel
+ pip wheel .
+)
+
+# This is needed to ensure we get a clean build, as otherwise parts of the
+# Python 3.8 package use compiled code for Python 3.7.
+bazel clean --expunge
+
+# Build wheel for Python 3.8
+(
+ # Set Path to Python3.8
+ export PATH=$PATH:/opt/python/cp38-cp38/bin
+
+ # Create binary wheel
+ pip wheel .
+)
+
+# Repair wheels to convert them from linux to manylinux.
+for wheel in ./tink*.whl; do
+ auditwheel repair "$wheel" -w release
+done
diff --git a/python/tools/distribution/create_release.sh b/python/tools/distribution/create_release.sh
new file mode 100755
index 0000000..df7ab72
--- /dev/null
+++ b/python/tools/distribution/create_release.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# This script creates a release of Tink Python which includes a source
+# distribution and binary wheels for Linux. The release script automatically
+# all Python tests on each binary wheel and the source distribution.
+set -euo pipefail
+
+mkdir -p release
+
+TINK_BASE=${PWD}/..
+
+# Use signatures for getting images from registry (see https://docs.docker.com/engine/security/trust/content_trust/)
+export DOCKER_CONTENT_TRUST=1
+
+# Build binary wheels
+docker run --volume $TINK_BASE:/tmp/tink --workdir /tmp/tink/python quay.io/pypa/manylinux2014_x86_64@sha256:cf8940dd5ce452d7741c592e229c28e802cbce5b3074d88a299e4f67f55efba4 /tmp/tink/python/tools/distribution/build_linux_binary_wheels.sh
+
+# Test binary wheels
+docker run --volume $TINK_BASE:/tmp/tink --workdir /tmp/tink/python quay.io/pypa/manylinux2014_x86_64@sha256:cf8940dd5ce452d7741c592e229c28e802cbce5b3074d88a299e4f67f55efba4 /tmp/tink/python/tools/distribution/test_linux_binary_wheels.sh
+
+# Build source wheels
+pip3 install wheel
+export TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH=$TINK_BASE
+sudo python3 setup.py sdist
+cp dist/*.tar.gz release/
+
+# Test install from source wheel
+pip3 install release/*.tar.gz
+find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 | xargs -0 -n1 python3
diff --git a/python/tools/distribution/test_linux_binary_wheels.sh b/python/tools/distribution/test_linux_binary_wheels.sh
new file mode 100755
index 0000000..b9befd2
--- /dev/null
+++ b/python/tools/distribution/test_linux_binary_wheels.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -euo pipefail
+
+export TINK_SRC_PATH=/tmp/tink
+
+# This link is required on CentOS, as curl used in the AWS SDK looks for the
+# certificates in this location. Removing this line will cause the AWS KMS tests
+# to fail.
+ln -s /etc/ssl/certs/ca-bundle.trust.crt /etc/ssl/certs/ca-certificates.crt
+
+# Test wheel for Python 3.7
+(
+ PATH=$PATH:/opt/python/cp37-cp37m/bin
+ pip3 install release/*-cp37-cp37m-manylinux2014_x86_64.whl
+ find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 | xargs -0 -n1 python3
+)
+
+# Test wheel for Python 3.8
+(
+ PATH=$PATH:/opt/python/cp38-cp38/bin
+ pip3 install release/*-cp38-cp38-manylinux2014_x86_64.whl
+ find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 | xargs -0 -n1 python3
+)
diff --git a/testing/cc/.bazelversion b/testing/cc/.bazelversion
new file mode 100644
index 0000000..fd2a018
--- /dev/null
+++ b/testing/cc/.bazelversion
@@ -0,0 +1 @@
+3.1.0
diff --git a/testing/cc/BUILD.bazel b/testing/cc/BUILD.bazel
new file mode 100644
index 0000000..caed1b1
--- /dev/null
+++ b/testing/cc/BUILD.bazel
@@ -0,0 +1,246 @@
+load("@rules_proto_grpc//cpp:defs.bzl", "cpp_grpc_library")
+
+package(
+ default_testonly = 1,
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"])
+
+cpp_grpc_library(
+ name = "testing_api_cpp_library",
+ service_namespace = "testing_api",
+ deps = ["@tink_base//proto/testing:testing_api_proto"],
+)
+
+cc_library(
+ name = "metadata_impl",
+ srcs = ["metadata_impl.cc"],
+ hdrs = ["metadata_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ ],
+)
+
+cc_test(
+ name = "metadata_impl_test",
+ srcs = ["metadata_impl_test.cc"],
+ deps = [
+ ":metadata_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "keyset_impl",
+ srcs = ["keyset_impl.cc"],
+ hdrs = ["keyset_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//:cleartext_keyset_handle",
+ "@tink_cc//:json_keyset_reader",
+ "@tink_cc//:json_keyset_writer",
+ "@tink_cc//:keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "keyset_impl_test",
+ srcs = ["keyset_impl_test.cc"],
+ deps = [
+ ":keyset_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//:json_keyset_reader",
+ "@tink_cc//:json_keyset_writer",
+ "@tink_cc//aead:aead_key_templates",
+ "@tink_cc//config:tink_config",
+ "@tink_cc//hybrid:hybrid_key_templates",
+ ],
+)
+
+cc_library(
+ name = "aead_impl",
+ srcs = ["aead_impl.cc"],
+ hdrs = ["aead_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "aead_impl_test",
+ srcs = ["aead_impl_test.cc"],
+ deps = [
+ ":aead_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//aead:aead_config",
+ "@tink_cc//aead:aead_key_templates",
+ ],
+)
+
+cc_library(
+ name = "deterministic_aead_impl",
+ srcs = ["deterministic_aead_impl.cc"],
+ hdrs = ["deterministic_aead_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "deterministic_aead_impl_test",
+ srcs = ["deterministic_aead_impl_test.cc"],
+ deps = [
+ ":deterministic_aead_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//daead:deterministic_aead_config",
+ "@tink_cc//daead:deterministic_aead_key_templates",
+ ],
+)
+
+cc_library(
+ name = "streaming_aead_impl",
+ srcs = ["streaming_aead_impl.cc"],
+ hdrs = ["streaming_aead_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ "@tink_cc//util:istream_input_stream",
+ "@tink_cc//util:ostream_output_stream",
+ "@tink_cc//util:status",
+ ],
+)
+
+cc_test(
+ name = "streaming_aead_impl_test",
+ srcs = ["streaming_aead_impl_test.cc"],
+ deps = [
+ ":streaming_aead_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//streamingaead:streaming_aead_config",
+ "@tink_cc//streamingaead:streaming_aead_key_templates",
+ ],
+)
+
+cc_library(
+ name = "mac_impl",
+ srcs = ["mac_impl.cc"],
+ hdrs = ["mac_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "mac_impl_test",
+ srcs = ["mac_impl_test.cc"],
+ deps = [
+ ":mac_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//mac:mac_config",
+ "@tink_cc//mac:mac_key_templates",
+ ],
+)
+
+cc_library(
+ name = "hybrid_impl",
+ srcs = ["hybrid_impl.cc"],
+ hdrs = ["hybrid_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "hybrid_impl_test",
+ srcs = ["hybrid_impl_test.cc"],
+ deps = [
+ ":hybrid_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//hybrid:hybrid_config",
+ "@tink_cc//hybrid:hybrid_key_templates",
+ ],
+)
+
+cc_library(
+ name = "signature_impl",
+ srcs = ["signature_impl.cc"],
+ hdrs = ["signature_impl.h"],
+ deps = [
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@tink_cc",
+ "@tink_cc//:binary_keyset_reader",
+ "@tink_cc//:cleartext_keyset_handle",
+ ],
+)
+
+cc_test(
+ name = "signature_impl_test",
+ srcs = ["signature_impl_test.cc"],
+ deps = [
+ ":signature_impl",
+ ":testing_api_cpp_library",
+ "@com_google_googletest//:gtest_main",
+ "@tink_cc//:binary_keyset_writer",
+ "@tink_cc//signature:signature_config",
+ "@tink_cc//signature:signature_key_templates",
+ ],
+)
+
+cc_binary(
+ name = "testing_server",
+ srcs = ["testing_server.cc"],
+ deps = [
+ ":aead_impl",
+ ":deterministic_aead_impl",
+ ":hybrid_impl",
+ ":keyset_impl",
+ ":mac_impl",
+ ":metadata_impl",
+ ":signature_impl",
+ ":streaming_aead_impl",
+ ":testing_api_cpp_library",
+ "@com_google_absl//absl/base:core_headers",
+ "@com_google_absl//absl/flags:flag",
+ "@com_google_absl//absl/flags:parse",
+ "@tink_cc//config:tink_config",
+ ],
+)
diff --git a/testing/cc/WORKSPACE b/testing/cc/WORKSPACE
new file mode 100644
index 0000000..c682047
--- /dev/null
+++ b/testing/cc/WORKSPACE
@@ -0,0 +1,42 @@
+workspace(name = "testing_cc")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "tink_base",
+ path = "../..",
+)
+
+local_repository(
+ name = "tink_cc",
+ path = "../../cc",
+)
+
+load("@tink_base//:tink_base_deps.bzl", "tink_base_deps")
+tink_base_deps()
+
+load("@tink_base//:tink_base_deps_init.bzl", "tink_base_deps_init")
+tink_base_deps_init()
+
+load("@tink_cc//:tink_cc_deps.bzl", "tink_cc_deps")
+tink_cc_deps()
+
+load("@tink_cc//:tink_cc_deps_init.bzl", "tink_cc_deps_init")
+tink_cc_deps_init()
+
+http_archive(
+ name = "rules_proto_grpc",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+)
+
+load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos")
+rules_proto_grpc_toolchains()
+rules_proto_grpc_repos()
+
+load("@rules_proto_grpc//cpp:repositories.bzl", rules_proto_grpc_cpp_repos="cpp_repos")
+rules_proto_grpc_cpp_repos()
+
+load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
+grpc_deps()
diff --git a/testing/cc/aead_impl.cc b/testing/cc/aead_impl.cc
new file mode 100644
index 0000000..16f35ed
--- /dev/null
+++ b/testing/cc/aead_impl.cc
@@ -0,0 +1,94 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of an AEAD Service.
+#include "aead_impl.h"
+
+#include "tink/aead.h"
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+AeadImpl::AeadImpl() {}
+
+// Encrypts a message
+::grpc::Status AeadImpl::Encrypt(grpc::ServerContext* context,
+ const AeadEncryptRequest* request,
+ AeadEncryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto aead_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::Aead>();
+ if (!aead_result.ok()) {
+ response->set_err(aead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto encrypt_result = aead_result.ValueOrDie()->Encrypt(
+ request->plaintext(), request->associated_data());
+ if (!encrypt_result.ok()) {
+ response->set_err(encrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_ciphertext(encrypt_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+// Decrypts a ciphertext
+::grpc::Status AeadImpl::Decrypt(grpc::ServerContext* context,
+ const AeadDecryptRequest* request,
+ AeadDecryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto aead_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::Aead>();
+ if (!aead_result.ok()) {
+ response->set_err(aead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto decrypt_result = aead_result.ValueOrDie()->Decrypt(
+ request->ciphertext(), request->associated_data());
+ if (!decrypt_result.ok()) {
+ response->set_err(decrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_plaintext(decrypt_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/aead_impl.h b/testing/cc/aead_impl.h
new file mode 100644
index 0000000..75bc274
--- /dev/null
+++ b/testing/cc/aead_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_SERIVCES_AEAD_IMPL_H_
+#define TINK_TESTING_SERIVCES_AEAD_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// An Aead Service.
+class AeadImpl final : public Aead::Service {
+ public:
+ AeadImpl();
+
+ ~AeadImpl() override = default;
+
+ grpc::Status Encrypt(grpc::ServerContext* context,
+ const AeadEncryptRequest* request,
+ AeadEncryptResponse* response) override;
+
+ grpc::Status Decrypt(grpc::ServerContext* context,
+ const AeadDecryptRequest* request,
+ AeadDecryptResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_SERIVCES_AEAD_IMPL_H_
diff --git a/testing/cc/aead_impl_test.cc b/testing/cc/aead_impl_test.cc
new file mode 100644
index 0000000..c5b0e60
--- /dev/null
+++ b/testing/cc/aead_impl_test.cc
@@ -0,0 +1,113 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "aead_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/aead/aead_config.h"
+#include "tink/aead/aead_key_templates.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::AeadKeyTemplates;
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::tink_testing_api::AeadDecryptRequest;
+using ::tink_testing_api::AeadEncryptRequest;
+using ::tink_testing_api::AeadEncryptResponse;
+using ::tink_testing_api::AeadDecryptResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string ValidKeyset() {
+ const KeyTemplate& key_template = AeadKeyTemplates::Aes128Eax();
+ auto handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(handle_result.ok());
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class AeadImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() { ASSERT_TRUE(AeadConfig::Register().ok()); }
+};
+
+TEST_F(AeadImplTest, EncryptDecryptSuccess) {
+ tink_testing_api::AeadImpl aead;
+ std::string keyset = ValidKeyset();
+ AeadEncryptRequest enc_request;
+ enc_request.set_keyset(keyset);
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ AeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(aead.Encrypt(nullptr, &enc_request, &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), IsEmpty());
+
+ AeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext(enc_response.ciphertext());
+ dec_request.set_associated_data("ad");
+ AeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(aead.Decrypt(nullptr, &dec_request, &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), IsEmpty());
+ EXPECT_THAT(dec_response.plaintext(), Eq("Plain text"));
+}
+
+TEST_F(AeadImplTest, EncryptBadKeysetFail) {
+ tink_testing_api::AeadImpl aead;
+ AeadEncryptRequest enc_request;
+ enc_request.set_keyset("bad keyset");
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ AeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(aead.Encrypt(nullptr, &enc_request, &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(AeadImplTest, DecryptBadCiphertextFail) {
+ tink_testing_api::AeadImpl aead;
+ std::string keyset = ValidKeyset();
+ AeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext("bad ciphertext");
+ dec_request.set_associated_data("ad");
+ AeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(aead.Decrypt(nullptr, &dec_request, &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/deterministic_aead_impl.cc b/testing/cc/deterministic_aead_impl.cc
new file mode 100644
index 0000000..a11d9e0
--- /dev/null
+++ b/testing/cc/deterministic_aead_impl.cc
@@ -0,0 +1,96 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of an Deterministic AEAD Service.
+#include "deterministic_aead_impl.h"
+
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/deterministic_aead.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+DeterministicAeadImpl::DeterministicAeadImpl() {}
+
+// Encrypts a message
+::grpc::Status DeterministicAeadImpl::EncryptDeterministically(
+ grpc::ServerContext* context,
+ const DeterministicAeadEncryptRequest* request,
+ DeterministicAeadEncryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto daead_result = handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::DeterministicAead>();
+ if (!daead_result.ok()) {
+ response->set_err(daead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto encrypt_result = daead_result.ValueOrDie()->EncryptDeterministically(
+ request->plaintext(), request->associated_data());
+ if (!encrypt_result.ok()) {
+ response->set_err(encrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_ciphertext(encrypt_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+// Decrypts a ciphertext
+::grpc::Status DeterministicAeadImpl::DecryptDeterministically(
+ grpc::ServerContext* context,
+ const DeterministicAeadDecryptRequest* request,
+ DeterministicAeadDecryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto daead_result = handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::DeterministicAead>();
+ if (!daead_result.ok()) {
+ response->set_err(daead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto decrypt_result = daead_result.ValueOrDie()->DecryptDeterministically(
+ request->ciphertext(), request->associated_data());
+ if (!decrypt_result.ok()) {
+ response->set_err(decrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_plaintext(decrypt_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/deterministic_aead_impl.h b/testing/cc/deterministic_aead_impl.h
new file mode 100644
index 0000000..ce23375
--- /dev/null
+++ b/testing/cc/deterministic_aead_impl.h
@@ -0,0 +1,46 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_SERIVCES_DETERMINISTIC_AEAD_IMPL_H_
+#define TINK_TESTING_SERIVCES_DETERMINISTIC_AEAD_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// An DeterministicAead Service.
+class DeterministicAeadImpl final : public DeterministicAead::Service {
+ public:
+ DeterministicAeadImpl();
+
+ ~DeterministicAeadImpl() override = default;
+
+ grpc::Status EncryptDeterministically(
+ grpc::ServerContext* context,
+ const DeterministicAeadEncryptRequest* request,
+ DeterministicAeadEncryptResponse* response) override;
+
+ grpc::Status DecryptDeterministically(
+ grpc::ServerContext* context,
+ const DeterministicAeadDecryptRequest* request,
+ DeterministicAeadDecryptResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_SERIVCES_DETERMINISTIC_AEAD_IMPL_H_
diff --git a/testing/cc/deterministic_aead_impl_test.cc b/testing/cc/deterministic_aead_impl_test.cc
new file mode 100644
index 0000000..af57073
--- /dev/null
+++ b/testing/cc/deterministic_aead_impl_test.cc
@@ -0,0 +1,123 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "deterministic_aead_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/daead/deterministic_aead_config.h"
+#include "tink/daead/deterministic_aead_key_templates.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::DeterministicAeadKeyTemplates;
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::tink_testing_api::DeterministicAeadDecryptRequest;
+using ::tink_testing_api::DeterministicAeadDecryptResponse;
+using ::tink_testing_api::DeterministicAeadEncryptRequest;
+using ::tink_testing_api::DeterministicAeadEncryptResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string ValidKeyset() {
+ const KeyTemplate& key_template = DeterministicAeadKeyTemplates::Aes256Siv();
+ auto handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(handle_result.ok());
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class DeterministicAeadImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() {
+ ASSERT_TRUE(DeterministicAeadConfig::Register().ok());
+ }
+};
+
+TEST_F(DeterministicAeadImplTest, EncryptDecryptSuccess) {
+ tink_testing_api::DeterministicAeadImpl daead;
+ std::string keyset = ValidKeyset();
+ DeterministicAeadEncryptRequest enc_request;
+ enc_request.set_keyset(keyset);
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ DeterministicAeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(
+ daead.EncryptDeterministically(nullptr, &enc_request, &enc_response)
+ .ok());
+ EXPECT_THAT(enc_response.err(), IsEmpty());
+
+ DeterministicAeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext(enc_response.ciphertext());
+ dec_request.set_associated_data("ad");
+ DeterministicAeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(
+ daead.DecryptDeterministically(nullptr, &dec_request, &dec_response)
+ .ok());
+ EXPECT_THAT(dec_response.err(), IsEmpty());
+ EXPECT_THAT(dec_response.plaintext(), Eq("Plain text"));
+}
+
+TEST_F(DeterministicAeadImplTest, EncryptBadKeysetFail) {
+ tink_testing_api::DeterministicAeadImpl daead;
+ DeterministicAeadEncryptRequest enc_request;
+ enc_request.set_keyset("bad keyset");
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ DeterministicAeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(
+ daead.EncryptDeterministically(nullptr, &enc_request, &enc_response)
+ .ok());
+ EXPECT_THAT(enc_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(DeterministicAeadImplTest, DecryptBadCiphertextFail) {
+ tink_testing_api::DeterministicAeadImpl daead;
+ std::string keyset = ValidKeyset();
+ DeterministicAeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext("bad ciphertext");
+ dec_request.set_associated_data("ad");
+ DeterministicAeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(
+ daead.DecryptDeterministically(nullptr, &dec_request, &dec_response)
+ .ok());
+ EXPECT_THAT(dec_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/hybrid_impl.cc b/testing/cc/hybrid_impl.cc
new file mode 100644
index 0000000..e20cf90
--- /dev/null
+++ b/testing/cc/hybrid_impl.cc
@@ -0,0 +1,97 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a Hybrid encryption service
+#include "hybrid_impl.h"
+
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/hybrid_decrypt.h"
+#include "tink/hybrid_encrypt.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+HybridImpl::HybridImpl() {}
+
+// Encrypts a message
+::grpc::Status HybridImpl::Encrypt(grpc::ServerContext* context,
+ const HybridEncryptRequest* request,
+ HybridEncryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->public_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto public_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!public_handle_result.ok()) {
+ response->set_err(public_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto hybrid_encrypt_result =
+ public_handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::HybridEncrypt>();
+ if (!hybrid_encrypt_result.ok()) {
+ response->set_err(hybrid_encrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto enc_result = hybrid_encrypt_result.ValueOrDie()->Encrypt(
+ request->plaintext(), request->context_info());
+ if (!enc_result.ok()) {
+ response->set_err(enc_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_ciphertext(enc_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+// Decrypts a ciphertext
+::grpc::Status HybridImpl::Decrypt(grpc::ServerContext* context,
+ const HybridDecryptRequest* request,
+ HybridDecryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->private_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto private_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!private_handle_result.ok()) {
+ response->set_err(private_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto hybrid_decrypt_result =
+ private_handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::HybridDecrypt>();
+ if (!hybrid_decrypt_result.ok()) {
+ response->set_err(hybrid_decrypt_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto dec_result = hybrid_decrypt_result.ValueOrDie()->Decrypt(
+ request->ciphertext(), request->context_info());
+ if (!dec_result.ok()) {
+ response->set_err(dec_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_plaintext(dec_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/hybrid_impl.h b/testing/cc/hybrid_impl.h
new file mode 100644
index 0000000..d05f29c
--- /dev/null
+++ b/testing/cc/hybrid_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_HYBRID_IMPL_H_
+#define TINK_TESTING_HYBRID_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A Hybrid encryption Service
+class HybridImpl final : public Hybrid::Service {
+ public:
+ HybridImpl();
+
+ ~HybridImpl() override = default;
+
+ grpc::Status Encrypt(grpc::ServerContext* context,
+ const HybridEncryptRequest* request,
+ HybridEncryptResponse* response) override;
+
+ grpc::Status Decrypt(grpc::ServerContext* context,
+ const HybridDecryptRequest* request,
+ HybridDecryptResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_HYBRID_IMPL_H_
diff --git a/testing/cc/hybrid_impl_test.cc b/testing/cc/hybrid_impl_test.cc
new file mode 100644
index 0000000..1cf4aab
--- /dev/null
+++ b/testing/cc/hybrid_impl_test.cc
@@ -0,0 +1,123 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "hybrid_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/hybrid/hybrid_config.h"
+#include "tink/hybrid/hybrid_key_templates.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::HybridKeyTemplates;
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::tink_testing_api::HybridDecryptRequest;
+using ::tink_testing_api::HybridDecryptResponse;
+using ::tink_testing_api::HybridEncryptRequest;
+using ::tink_testing_api::HybridEncryptResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string KeysetBytes(const KeysetHandle& keyset_handle) {
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ keyset_handle);
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class HybridImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() { ASSERT_TRUE(HybridConfig::Register().ok()); }
+};
+
+TEST_F(HybridImplTest, EncryptDecryptSuccess) {
+ tink_testing_api::HybridImpl hybrid;
+ const KeyTemplate& key_template =
+ HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm();
+ auto private_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(private_handle_result.ok());
+ auto public_handle_result =
+ private_handle_result.ValueOrDie()->GetPublicKeysetHandle();
+ EXPECT_TRUE(public_handle_result.ok());
+
+ HybridEncryptRequest enc_request;
+ enc_request.set_public_keyset(
+ KeysetBytes(*public_handle_result.ValueOrDie()));
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_context_info("context");
+ HybridEncryptResponse enc_response;
+
+ EXPECT_TRUE(hybrid.Encrypt(nullptr, &enc_request, &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), IsEmpty());
+
+ HybridDecryptRequest dec_request;
+ dec_request.set_private_keyset(
+ KeysetBytes(*private_handle_result.ValueOrDie()));
+ dec_request.set_ciphertext(enc_response.ciphertext());
+ dec_request.set_context_info("context");
+ HybridDecryptResponse dec_response;
+
+ EXPECT_TRUE(hybrid.Decrypt(nullptr, &dec_request, &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), IsEmpty());
+ EXPECT_THAT(dec_response.plaintext(), Eq("Plain text"));
+}
+
+TEST_F(HybridImplTest, EncryptBadKeysetFail) {
+ tink_testing_api::HybridImpl hybrid;
+ HybridEncryptRequest enc_request;
+ enc_request.set_public_keyset("bad keyset");
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_context_info("context");
+ HybridEncryptResponse enc_response;
+
+ EXPECT_TRUE(hybrid.Encrypt(nullptr, &enc_request, &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(HybridImplTest, DecryptBadCiphertextFail) {
+ tink_testing_api::HybridImpl hybrid;
+ const KeyTemplate& key_template =
+ HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm();
+ auto private_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(private_handle_result.ok());
+
+ HybridDecryptRequest dec_request;
+ dec_request.set_private_keyset(
+ KeysetBytes(*private_handle_result.ValueOrDie()));
+ dec_request.set_ciphertext("bad ciphertext");
+ dec_request.set_context_info("context");
+ HybridDecryptResponse dec_response;
+
+ EXPECT_TRUE(hybrid.Decrypt(nullptr, &dec_request, &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/keyset_impl.cc b/testing/cc/keyset_impl.cc
new file mode 100644
index 0000000..0612f61
--- /dev/null
+++ b/testing/cc/keyset_impl.cc
@@ -0,0 +1,173 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a Keyset Service.
+#include "keyset_impl.h"
+
+#include "tink/binary_keyset_reader.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/json_keyset_reader.h"
+#include "tink/json_keyset_writer.h"
+#include "tink/keyset_handle.h"
+#include "proto/tink.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::JsonKeysetReader;
+using ::crypto::tink::JsonKeysetWriter;
+using ::crypto::tink::KeysetHandle;
+using ::google::crypto::tink::KeyTemplate;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+KeysetImpl::KeysetImpl() {}
+
+// Generates a new keyset with one key from a template.
+::grpc::Status KeysetImpl::Generate(grpc::ServerContext* context,
+ const KeysetGenerateRequest* request,
+ KeysetGenerateResponse* response) {
+ KeyTemplate key_template;
+ if (!key_template.ParseFromString(request->template_())) {
+ response->set_err("Could not parse the key template");
+ return ::grpc::Status::OK;
+ }
+ auto handle_result = KeysetHandle::GenerateNew(key_template);
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ if (!writer_result.ok()) {
+ response->set_err(writer_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_keyset(keyset.str());
+ return ::grpc::Status::OK;
+}
+
+// Returns a public keyset for a given private keyset.
+::grpc::Status KeysetImpl::Public(grpc::ServerContext* context,
+ const KeysetPublicRequest* request,
+ KeysetPublicResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->private_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto private_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!private_handle_result.ok()) {
+ response->set_err(private_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto public_handle_result =
+ private_handle_result.ValueOrDie()->GetPublicKeysetHandle();
+ if (!public_handle_result.ok()) {
+ response->set_err(public_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ std::stringbuf public_keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&public_keyset));
+ if (!writer_result.ok()) {
+ response->set_err(writer_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status = CleartextKeysetHandle::Write(
+ writer_result.ValueOrDie().get(), *public_handle_result.ValueOrDie());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_public_keyset(public_keyset.str());
+ return ::grpc::Status::OK;
+}
+
+// Converts a keyset from binary to JSON format.
+::grpc::Status KeysetImpl::ToJson(grpc::ServerContext* context,
+ const KeysetToJsonRequest* request,
+ KeysetToJsonResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ std::stringbuf json_keyset;
+ auto writer_result =
+ JsonKeysetWriter::New(absl::make_unique<std::ostream>(&json_keyset));
+ if (!writer_result.ok()) {
+ response->set_err(writer_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_json_keyset(json_keyset.str());
+ return ::grpc::Status::OK;
+}
+
+// Converts a keyset from JSON to binary format.
+::grpc::Status KeysetImpl::FromJson(grpc::ServerContext* context,
+ const KeysetFromJsonRequest* request,
+ KeysetFromJsonResponse* response) {
+ auto reader_result = JsonKeysetReader::New(request->json_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ if (!writer_result.ok()) {
+ response->set_err(writer_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_keyset(keyset.str());
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/keyset_impl.h b/testing/cc/keyset_impl.h
new file mode 100644
index 0000000..83674f4
--- /dev/null
+++ b/testing/cc/keyset_impl.h
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_SERIVCES_KEYSET_IMPL_H_
+#define TINK_TESTING_SERIVCES_KEYSET_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A Keyset Service.
+class KeysetImpl final : public Keyset::Service {
+ public:
+ KeysetImpl();
+
+ ~KeysetImpl() override = default;
+
+ // Generates a new keyset with one key from a template.
+ grpc::Status Generate(grpc::ServerContext* context,
+ const KeysetGenerateRequest* request,
+ KeysetGenerateResponse* response) override;
+
+ // Returns a public keyset for a given private keyset.
+ grpc::Status Public(grpc::ServerContext* context,
+ const KeysetPublicRequest* request,
+ KeysetPublicResponse* response) override;
+
+ // Converts a keyset from binary to JSON format.
+ grpc::Status ToJson(grpc::ServerContext* context,
+ const KeysetToJsonRequest* request,
+ KeysetToJsonResponse* response) override;
+
+ // Converts a keyset from JSON to binary format.
+ grpc::Status FromJson(grpc::ServerContext* context,
+ const KeysetFromJsonRequest* request,
+ KeysetFromJsonResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_SERIVCES_KEYSET_IMPL_H_
diff --git a/testing/cc/keyset_impl_test.cc b/testing/cc/keyset_impl_test.cc
new file mode 100644
index 0000000..248adfe
--- /dev/null
+++ b/testing/cc/keyset_impl_test.cc
@@ -0,0 +1,198 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "keyset_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/aead/aead_key_templates.h"
+#include "tink/binary_keyset_reader.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/config/tink_config.h"
+#include "tink/hybrid/hybrid_key_templates.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::AeadKeyTemplates;
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::HybridKeyTemplates;
+using google::crypto::tink::KeyTemplate;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using tink_testing_api::KeysetFromJsonRequest;
+using tink_testing_api::KeysetFromJsonResponse;
+using tink_testing_api::KeysetGenerateRequest;
+using tink_testing_api::KeysetGenerateResponse;
+using tink_testing_api::KeysetPublicRequest;
+using tink_testing_api::KeysetPublicResponse;
+using tink_testing_api::KeysetToJsonRequest;
+using tink_testing_api::KeysetToJsonResponse;
+
+class KeysetImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() { ASSERT_TRUE(TinkConfig::Register().ok()); }
+};
+
+TEST_F(KeysetImplTest, GenerateSuccess) {
+ tink_testing_api::KeysetImpl keyset;
+ const KeyTemplate& key_template = AeadKeyTemplates::Aes128Eax();
+ KeysetGenerateRequest request;
+ std::string templ;
+ EXPECT_TRUE(key_template.SerializeToString(&templ));
+ request.set_template_(templ);
+ KeysetGenerateResponse response;
+
+ EXPECT_TRUE(keyset.Generate(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), IsEmpty());
+
+ auto reader_result = BinaryKeysetReader::New(response.keyset());
+ ASSERT_TRUE(reader_result.ok());
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ EXPECT_TRUE(handle_result.ok());
+}
+
+TEST_F(KeysetImplTest, GenerateFail) {
+ tink_testing_api::KeysetImpl keyset;
+
+ KeysetGenerateRequest request;
+ request.set_template_("bad template");
+ KeysetGenerateResponse response;
+ EXPECT_TRUE(keyset.Generate(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), Not(IsEmpty()));
+}
+
+std::string ValidPrivateKeyset() {
+ auto handle_result = KeysetHandle::GenerateNew(
+ HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm());
+ EXPECT_TRUE(handle_result.ok());
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+TEST_F(KeysetImplTest, PublicSuccess) {
+ tink_testing_api::KeysetImpl keyset;
+
+ KeysetPublicRequest request;
+ request.set_private_keyset(ValidPrivateKeyset());
+ KeysetPublicResponse response;
+
+ EXPECT_TRUE(keyset.Public(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), IsEmpty());
+
+ auto reader_result = BinaryKeysetReader::New(response.public_keyset());
+ ASSERT_TRUE(reader_result.ok());
+ auto public_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ EXPECT_TRUE(public_handle_result.ok());
+}
+
+TEST_F(KeysetImplTest, PublicFail) {
+ tink_testing_api::KeysetImpl keyset;
+
+ KeysetPublicRequest request;
+ request.set_private_keyset("bad keyset");
+ KeysetPublicResponse response;
+ EXPECT_TRUE(keyset.Public(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), Not(IsEmpty()));
+}
+
+TEST_F(KeysetImplTest, FromJsonSuccess) {
+ tink_testing_api::KeysetImpl keyset;
+ std::string json_keyset = R""""(
+ {
+ "primaryKeyId": 42,
+ "key": [
+ {
+ "keyData": {
+ "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
+ "keyMaterialType": "SYMMETRIC",
+ "value": "AFakeTestKeyValue1234567"
+ },
+ "outputPrefixType": "TINK",
+ "keyId": 42,
+ "status": "ENABLED"
+ }
+ ]
+ })"""";
+ KeysetFromJsonRequest from_request;
+ from_request.set_json_keyset(json_keyset);
+ KeysetFromJsonResponse from_response;
+ EXPECT_TRUE(keyset.FromJson(nullptr, &from_request, &from_response).ok());
+ EXPECT_THAT(from_response.err(), IsEmpty());
+ std::string output = from_response.keyset();
+
+ auto reader_result = BinaryKeysetReader::New(from_response.keyset());
+ EXPECT_TRUE(reader_result.ok());
+ auto keyset_proto_result = reader_result.ValueOrDie()->Read();
+ EXPECT_TRUE(keyset_proto_result.ok());
+ EXPECT_THAT(keyset_proto_result.ValueOrDie()->primary_key_id(), Eq(42));
+}
+
+TEST_F(KeysetImplTest, ToFromJsonSuccess) {
+ tink_testing_api::KeysetImpl keyset;
+ std::string keyset_data = ValidPrivateKeyset();
+
+ KeysetToJsonRequest to_request;
+ to_request.set_keyset(keyset_data);
+ KeysetToJsonResponse to_response;
+ EXPECT_TRUE(keyset.ToJson(nullptr, &to_request, &to_response).ok());
+ EXPECT_THAT(to_response.err(), IsEmpty());
+ std::string json_keyset = to_response.json_keyset();
+
+ KeysetFromJsonRequest from_request;
+ from_request.set_json_keyset(json_keyset);
+ KeysetFromJsonResponse from_response;
+ EXPECT_TRUE(keyset.FromJson(nullptr, &from_request, &from_response).ok());
+ EXPECT_THAT(from_response.err(), IsEmpty());
+ std::string output = from_response.keyset();
+ EXPECT_THAT(from_response.keyset(), Eq(keyset_data));
+}
+
+TEST_F(KeysetImplTest, ToJsonFail) {
+ tink_testing_api::KeysetImpl keyset;
+
+ KeysetToJsonRequest request;
+ request.set_keyset("bad keyset");
+ KeysetToJsonResponse response;
+ EXPECT_TRUE(keyset.ToJson(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), Not(IsEmpty()));
+}
+
+TEST_F(KeysetImplTest, FromJsonFail) {
+ tink_testing_api::KeysetImpl keyset;
+
+ KeysetFromJsonRequest request;
+ request.set_json_keyset("bad json keyset");
+ KeysetFromJsonResponse response;
+ EXPECT_TRUE(keyset.FromJson(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/mac_impl.cc b/testing/cc/mac_impl.cc
new file mode 100644
index 0000000..500263c
--- /dev/null
+++ b/testing/cc/mac_impl.cc
@@ -0,0 +1,92 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a MAC Service.
+#include "mac_impl.h"
+
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/mac.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+MacImpl::MacImpl() {}
+
+// Computes a MAC
+::grpc::Status MacImpl::ComputeMac(grpc::ServerContext* context,
+ const ComputeMacRequest* request,
+ ComputeMacResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto mac_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::Mac>();
+ if (!mac_result.ok()) {
+ response->set_err(mac_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto compute_result = mac_result.ValueOrDie()->ComputeMac(request->data());
+ if (!compute_result.ok()) {
+ response->set_err(compute_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_mac_value(compute_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+// Verifies a MAC
+::grpc::Status MacImpl::VerifyMac(grpc::ServerContext* context,
+ const VerifyMacRequest* request,
+ VerifyMacResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto mac_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::Mac>();
+ if (!mac_result.ok()) {
+ response->set_err(mac_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status =
+ mac_result.ValueOrDie()->VerifyMac(request->mac_value(), request->data());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/mac_impl.h b/testing/cc/mac_impl.h
new file mode 100644
index 0000000..ebe9e7c
--- /dev/null
+++ b/testing/cc/mac_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_MAC_IMPL_H_
+#define TINK_TESTING_MAC_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A MAC Service.
+class MacImpl final : public Mac::Service {
+ public:
+ MacImpl();
+
+ ~MacImpl() override = default;
+
+ grpc::Status ComputeMac(grpc::ServerContext* context,
+ const ComputeMacRequest* request,
+ ComputeMacResponse* response) override;
+
+ grpc::Status VerifyMac(grpc::ServerContext* context,
+ const VerifyMacRequest* request,
+ VerifyMacResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_MAC_IMPL_H_
diff --git a/testing/cc/mac_impl_test.cc b/testing/cc/mac_impl_test.cc
new file mode 100644
index 0000000..480aa81
--- /dev/null
+++ b/testing/cc/mac_impl_test.cc
@@ -0,0 +1,109 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "mac_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/mac/mac_config.h"
+#include "tink/mac/mac_key_templates.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::MacKeyTemplates;
+
+using ::testing::IsEmpty;
+using ::tink_testing_api::ComputeMacRequest;
+using ::tink_testing_api::ComputeMacResponse;
+using ::tink_testing_api::VerifyMacRequest;
+using ::tink_testing_api::VerifyMacResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string ValidKeyset() {
+ const KeyTemplate& key_template = MacKeyTemplates::HmacSha256();
+ auto handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(handle_result.ok());
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class MacImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() { ASSERT_TRUE(MacConfig::Register().ok()); }
+};
+
+TEST_F(MacImplTest, ComputeVerifySuccess) {
+ tink_testing_api::MacImpl mac;
+ std::string keyset = ValidKeyset();
+ ComputeMacRequest comp_request;
+ comp_request.set_keyset(keyset);
+ comp_request.set_data("some data");
+ ComputeMacResponse comp_response;
+
+ EXPECT_TRUE(mac.ComputeMac(nullptr, &comp_request, &comp_response).ok());
+ EXPECT_THAT(comp_response.err(), IsEmpty());
+
+ VerifyMacRequest verify_request;
+ verify_request.set_keyset(keyset);
+ verify_request.set_mac_value(comp_response.mac_value());
+ verify_request.set_data("some data");
+ VerifyMacResponse verify_response;
+
+ EXPECT_TRUE(mac.VerifyMac(nullptr, &verify_request, &verify_response).ok());
+ EXPECT_THAT(verify_response.err(), IsEmpty());
+}
+
+TEST_F(MacImplTest, ComputeBadKeysetFail) {
+ tink_testing_api::MacImpl mac;
+ ComputeMacRequest comp_request;
+ comp_request.set_keyset("bad keyset");
+ comp_request.set_data("some data");
+ ComputeMacResponse comp_response;
+
+ EXPECT_TRUE(mac.ComputeMac(nullptr, &comp_request, &comp_response).ok());
+ EXPECT_THAT(comp_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(MacImplTest, VerifyBadCiphertextFail) {
+ tink_testing_api::MacImpl mac;
+ std::string keyset = ValidKeyset();
+ VerifyMacRequest verify_request;
+ verify_request.set_keyset(keyset);
+ verify_request.set_mac_value("bad mac value");
+ verify_request.set_data("some data");
+ VerifyMacResponse verify_response;
+
+ EXPECT_TRUE(mac.VerifyMac(nullptr, &verify_request, &verify_response).ok());
+ EXPECT_THAT(verify_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/metadata_impl.cc b/testing/cc/metadata_impl.cc
new file mode 100644
index 0000000..5d742a6
--- /dev/null
+++ b/testing/cc/metadata_impl.cc
@@ -0,0 +1,35 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a server metadata service.
+#include "metadata_impl.h"
+#include "tink/version.h"
+
+namespace tink_testing_api {
+
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+MetadataImpl::MetadataImpl() {}
+
+// Returns server info.
+grpc::Status MetadataImpl::GetServerInfo(grpc::ServerContext* context,
+ const ServerInfoRequest* request,
+ ServerInfoResponse* response) {
+ response->set_language("cc");
+ response->set_tink_version(crypto::tink::Version::kTinkVersion);
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/metadata_impl.h b/testing/cc/metadata_impl.h
new file mode 100644
index 0000000..1a2fa8c
--- /dev/null
+++ b/testing/cc/metadata_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_METADATA_IMPL_H_
+#define TINK_TESTING_METADATA_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A Metadata Service.
+class MetadataImpl final : public Metadata::Service {
+ public:
+ MetadataImpl();
+
+ ~MetadataImpl() override = default;
+
+ // Returns server info.
+ grpc::Status GetServerInfo(grpc::ServerContext* context,
+ const ServerInfoRequest* request,
+ ServerInfoResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+
+
+
+#endif // TINK_TESTING_METADATA_IMPL_H_
diff --git a/testing/cc/metadata_impl_test.cc b/testing/cc/metadata_impl_test.cc
new file mode 100644
index 0000000..a5ab828
--- /dev/null
+++ b/testing/cc/metadata_impl_test.cc
@@ -0,0 +1,41 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "metadata_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using tink_testing_api::ServerInfoRequest;
+using tink_testing_api::ServerInfoResponse;
+
+TEST(MetadataImplTest, GetServerInfo) {
+ tink_testing_api::MetadataImpl metadata;
+ ServerInfoRequest request;
+ ServerInfoResponse response;
+ EXPECT_TRUE(metadata.GetServerInfo(nullptr, &request, &response).ok());
+ EXPECT_THAT(response.language(), Eq("cc"));
+ EXPECT_THAT(response.tink_version(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/signature_impl.cc b/testing/cc/signature_impl.cc
new file mode 100644
index 0000000..0d1c44c
--- /dev/null
+++ b/testing/cc/signature_impl.cc
@@ -0,0 +1,93 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a Signature Service
+#include "signature_impl.h"
+
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/public_key_sign.h"
+#include "tink/public_key_verify.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+SignatureImpl::SignatureImpl() {}
+
+// Signs a message
+::grpc::Status SignatureImpl::Sign(grpc::ServerContext* context,
+ const SignatureSignRequest* request,
+ SignatureSignResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->private_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto private_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!private_handle_result.ok()) {
+ response->set_err(private_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto signer_result = private_handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::PublicKeySign>();
+ if (!signer_result.ok()) {
+ response->set_err(signer_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto sign_result = signer_result.ValueOrDie()->Sign(request->data());
+ if (!sign_result.ok()) {
+ response->set_err(sign_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ response->set_signature(sign_result.ValueOrDie());
+ return ::grpc::Status::OK;
+}
+
+// Verifies a signature
+::grpc::Status SignatureImpl::Verify(grpc::ServerContext* context,
+ const SignatureVerifyRequest* request,
+ SignatureVerifyResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->public_keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto public_handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!public_handle_result.ok()) {
+ response->set_err(public_handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto verifier_result = public_handle_result.ValueOrDie()
+ ->GetPrimitive<crypto::tink::PublicKeyVerify>();
+ if (!verifier_result.ok()) {
+ response->set_err(verifier_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto status = verifier_result.ValueOrDie()->Verify(request->signature(),
+ request->data());
+ if (!status.ok()) {
+ response->set_err(status.error_message());
+ return ::grpc::Status::OK;
+ }
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/signature_impl.h b/testing/cc/signature_impl.h
new file mode 100644
index 0000000..dd4d952
--- /dev/null
+++ b/testing/cc/signature_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_SIGNATURE_IMPL_H_
+#define TINK_TESTING_SIGNATURE_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A Signature Service
+class SignatureImpl final : public Signature::Service {
+ public:
+ SignatureImpl();
+
+ ~SignatureImpl() override = default;
+
+ grpc::Status Sign(grpc::ServerContext* context,
+ const SignatureSignRequest* request,
+ SignatureSignResponse* response) override;
+
+ grpc::Status Verify(grpc::ServerContext* context,
+ const SignatureVerifyRequest* request,
+ SignatureVerifyResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_SIGNATURE_IMPL_H_
diff --git a/testing/cc/signature_impl_test.cc b/testing/cc/signature_impl_test.cc
new file mode 100644
index 0000000..ce7cf83
--- /dev/null
+++ b/testing/cc/signature_impl_test.cc
@@ -0,0 +1,124 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "signature_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/signature/signature_config.h"
+#include "tink/signature/signature_key_templates.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::SignatureKeyTemplates;
+
+using ::testing::IsEmpty;
+using ::tink_testing_api::SignatureSignRequest;
+using ::tink_testing_api::SignatureSignResponse;
+using ::tink_testing_api::SignatureVerifyRequest;
+using ::tink_testing_api::SignatureVerifyResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string KeysetBytes(const KeysetHandle& keyset_handle) {
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ keyset_handle);
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class SignatureImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() {
+ ASSERT_TRUE(SignatureConfig::Register().ok());
+ }
+};
+
+TEST_F(SignatureImplTest, SignVerifySuccess) {
+ tink_testing_api::SignatureImpl signature;
+ const KeyTemplate& key_template = SignatureKeyTemplates::EcdsaP256();
+ auto private_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(private_handle_result.ok());
+ auto public_handle_result =
+ private_handle_result.ValueOrDie()->GetPublicKeysetHandle();
+ EXPECT_TRUE(public_handle_result.ok());
+
+ SignatureSignRequest sign_request;
+ sign_request.set_private_keyset(
+ KeysetBytes(*private_handle_result.ValueOrDie()));
+ sign_request.set_data("some data");
+ SignatureSignResponse sign_response;
+
+ EXPECT_TRUE(signature.Sign(nullptr, &sign_request, &sign_response).ok());
+ EXPECT_THAT(sign_response.err(), IsEmpty());
+
+ SignatureVerifyRequest verify_request;
+ verify_request.set_public_keyset(
+ KeysetBytes(*public_handle_result.ValueOrDie()));
+ verify_request.set_signature(sign_response.signature());
+ verify_request.set_data("some data");
+ SignatureVerifyResponse verify_response;
+
+ EXPECT_TRUE(
+ signature.Verify(nullptr, &verify_request, &verify_response).ok());
+ EXPECT_THAT(verify_response.err(), IsEmpty());
+}
+
+TEST_F(SignatureImplTest, SignBadKeysetFail) {
+ tink_testing_api::SignatureImpl signature;
+ SignatureSignRequest sign_request;
+ sign_request.set_private_keyset("bad private keyset");
+ sign_request.set_data("some data");
+ SignatureSignResponse sign_response;
+
+ EXPECT_TRUE(signature.Sign(nullptr, &sign_request, &sign_response).ok());
+ EXPECT_THAT(sign_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(SignatureImplTest, VerifyBadCiphertextFail) {
+ tink_testing_api::SignatureImpl signature;
+ const KeyTemplate& key_template = SignatureKeyTemplates::EcdsaP256();
+ auto private_handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(private_handle_result.ok());
+ auto public_handle_result =
+ private_handle_result.ValueOrDie()->GetPublicKeysetHandle();
+ EXPECT_TRUE(public_handle_result.ok());
+
+ SignatureVerifyRequest verify_request;
+ verify_request.set_public_keyset(
+ KeysetBytes(*public_handle_result.ValueOrDie()));
+ verify_request.set_signature("bad signature");
+ verify_request.set_data("some data");
+ SignatureVerifyResponse verify_response;
+
+ EXPECT_TRUE(
+ signature.Verify(nullptr, &verify_request, &verify_response).ok());
+ EXPECT_THAT(verify_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/streaming_aead_impl.cc b/testing/cc/streaming_aead_impl.cc
new file mode 100644
index 0000000..3dd1a70
--- /dev/null
+++ b/testing/cc/streaming_aead_impl.cc
@@ -0,0 +1,169 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Implementation of a StreamingAEAD Service.
+#include "streaming_aead_impl.h"
+
+#include "tink/streaming_aead.h"
+#include "tink/binary_keyset_reader.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "tink/util/istream_input_stream.h"
+#include "tink/util/ostream_output_stream.h"
+#include "tink/util/status.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+namespace tinkutil = ::crypto::tink::util;
+
+using ::crypto::tink::BinaryKeysetReader;
+using ::crypto::tink::CleartextKeysetHandle;
+using ::crypto::tink::InputStream;
+using ::crypto::tink::util::IstreamInputStream;
+using ::crypto::tink::util::OstreamOutputStream;
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+
+StreamingAeadImpl::StreamingAeadImpl() {}
+
+// Encrypts a message
+::grpc::Status StreamingAeadImpl::Encrypt(
+ grpc::ServerContext* context,
+ const StreamingAeadEncryptRequest* request,
+ StreamingAeadEncryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto streaming_aead_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::StreamingAead>();
+ if (!streaming_aead_result.ok()) {
+ response->set_err(streaming_aead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+
+ auto ciphertext_stream = absl::make_unique<std::stringstream>();
+ auto ciphertext_buf = ciphertext_stream->rdbuf();
+ auto ciphertext_destination(
+ absl::make_unique<OstreamOutputStream>(std::move(ciphertext_stream)));
+
+ auto encrypting_stream_result =
+ streaming_aead_result.ValueOrDie()->NewEncryptingStream(
+ std::move(ciphertext_destination), request->associated_data());
+ if (!encrypting_stream_result.ok()) {
+ response->set_err(encrypting_stream_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto encrypting_stream = std::move(encrypting_stream_result.ValueOrDie());
+
+ auto contents = request->plaintext();
+ void* buffer;
+ int pos = 0;
+ int remaining = contents.length();
+ int available_space = 0;
+ int available_bytes = 0;
+ while (remaining > 0) {
+ auto next_result = encrypting_stream->Next(&buffer);
+ if (!next_result.ok()) {
+ response->set_err(next_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ available_space = next_result.ValueOrDie();
+ available_bytes = std::min(available_space, remaining);
+ memcpy(buffer, contents.data() + pos, available_bytes);
+ remaining -= available_bytes;
+ pos += available_bytes;
+ }
+ if (available_space > available_bytes) {
+ encrypting_stream->BackUp(available_space - available_bytes);
+ }
+ auto close_status = encrypting_stream->Close();
+ if (!close_status.ok()) {
+ response->set_err(close_status.error_message());
+ return ::grpc::Status::OK;
+ }
+
+ response->set_ciphertext(ciphertext_buf->str());
+ return ::grpc::Status::OK;
+}
+
+// Decrypts a ciphertext
+::grpc::Status StreamingAeadImpl::Decrypt(
+ grpc::ServerContext* context,
+ const StreamingAeadDecryptRequest* request,
+ StreamingAeadDecryptResponse* response) {
+ auto reader_result = BinaryKeysetReader::New(request->keyset());
+ if (!reader_result.ok()) {
+ response->set_err(reader_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto handle_result =
+ CleartextKeysetHandle::Read(std::move(reader_result.ValueOrDie()));
+ if (!handle_result.ok()) {
+ response->set_err(handle_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto streaming_aead_result =
+ handle_result.ValueOrDie()->GetPrimitive<crypto::tink::StreamingAead>();
+ if (!streaming_aead_result.ok()) {
+ response->set_err(streaming_aead_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+
+ auto ciphertext_stream =
+ absl::make_unique<std::stringstream>(request->ciphertext());
+ std::unique_ptr<InputStream> ciphertext_source(
+ absl::make_unique<IstreamInputStream>(std::move(ciphertext_stream)));
+
+ auto decrypting_stream_result =
+ streaming_aead_result.ValueOrDie()->NewDecryptingStream(
+ std::move(ciphertext_source), request->associated_data());
+ if (!decrypting_stream_result.ok()) {
+ response->set_err(decrypting_stream_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto decrypting_stream = std::move(decrypting_stream_result.ValueOrDie());
+
+ std::string plaintext;
+ const void* buffer;
+ while (true) {
+ auto next_result = decrypting_stream->Next(&buffer);
+ if (next_result.status().error_code() == tinkutil::error::OUT_OF_RANGE) {
+ // End of stream.
+ break;
+ }
+ if (!next_result.ok()) {
+ response->set_err(next_result.status().error_message());
+ return ::grpc::Status::OK;
+ }
+ auto read_bytes = next_result.ValueOrDie();
+ if (read_bytes > 0) {
+ plaintext.append(
+ std::string(reinterpret_cast<const char*>(buffer), read_bytes));
+ }
+ }
+
+ response->set_plaintext(plaintext);
+ return ::grpc::Status::OK;
+}
+
+} // namespace tink_testing_api
diff --git a/testing/cc/streaming_aead_impl.h b/testing/cc/streaming_aead_impl.h
new file mode 100644
index 0000000..6323cc9
--- /dev/null
+++ b/testing/cc/streaming_aead_impl.h
@@ -0,0 +1,44 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_TESTING_SERIVCES_STREAMING_AEAD_IMPL_H_
+#define TINK_TESTING_SERIVCES_STREAMING_AEAD_IMPL_H_
+
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/status.h>
+
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace tink_testing_api {
+
+// A StreamingAead Service.
+class StreamingAeadImpl final : public StreamingAead::Service {
+ public:
+ StreamingAeadImpl();
+
+ ~StreamingAeadImpl() override = default;
+
+ grpc::Status Encrypt(grpc::ServerContext* context,
+ const StreamingAeadEncryptRequest* request,
+ StreamingAeadEncryptResponse* response) override;
+
+ grpc::Status Decrypt(grpc::ServerContext* context,
+ const StreamingAeadDecryptRequest* request,
+ StreamingAeadDecryptResponse* response) override;
+};
+
+} // namespace tink_testing_api
+
+#endif // TINK_TESTING_SERIVCES_STREAMING_AEAD_IMPL_H_
diff --git a/testing/cc/streaming_aead_impl_test.cc b/testing/cc/streaming_aead_impl_test.cc
new file mode 100644
index 0000000..7af00ba
--- /dev/null
+++ b/testing/cc/streaming_aead_impl_test.cc
@@ -0,0 +1,120 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "streaming_aead_impl.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/streamingaead/streaming_aead_config.h"
+#include "tink/streamingaead/streaming_aead_key_templates.h"
+#include "tink/binary_keyset_writer.h"
+#include "tink/cleartext_keyset_handle.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::StreamingAeadKeyTemplates;
+using ::crypto::tink::BinaryKeysetWriter;
+using ::crypto::tink::CleartextKeysetHandle;
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::tink_testing_api::StreamingAeadDecryptRequest;
+using ::tink_testing_api::StreamingAeadEncryptRequest;
+using ::tink_testing_api::StreamingAeadEncryptResponse;
+using ::tink_testing_api::StreamingAeadDecryptResponse;
+
+using crypto::tink::KeysetHandle;
+using google::crypto::tink::KeyTemplate;
+
+std::string ValidKeyset() {
+ const KeyTemplate& key_template =
+ StreamingAeadKeyTemplates::Aes128GcmHkdf4KB();
+ auto handle_result = KeysetHandle::GenerateNew(key_template);
+ EXPECT_TRUE(handle_result.ok());
+ std::stringbuf keyset;
+ auto writer_result =
+ BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset));
+ EXPECT_TRUE(writer_result.ok());
+
+ auto status = CleartextKeysetHandle::Write(writer_result.ValueOrDie().get(),
+ *handle_result.ValueOrDie());
+ EXPECT_TRUE(status.ok());
+ return keyset.str();
+}
+
+class StreamingAeadImplTest : public ::testing::Test {
+ protected:
+ static void SetUpTestSuite() {
+ ASSERT_TRUE(StreamingAeadConfig::Register().ok());
+ }
+};
+
+TEST_F(StreamingAeadImplTest, EncryptDecryptSuccess) {
+ tink_testing_api::StreamingAeadImpl streaming_aead;
+ std::string keyset = ValidKeyset();
+ StreamingAeadEncryptRequest enc_request;
+ enc_request.set_keyset(keyset);
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ StreamingAeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(streaming_aead.Encrypt(nullptr, &enc_request,
+ &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), IsEmpty());
+
+ StreamingAeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext(enc_response.ciphertext());
+ dec_request.set_associated_data("ad");
+ StreamingAeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(streaming_aead.Decrypt(nullptr, &dec_request,
+ &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), IsEmpty());
+ EXPECT_THAT(dec_response.plaintext(), Eq("Plain text"));
+}
+
+TEST_F(StreamingAeadImplTest, EncryptBadKeysetFail) {
+ tink_testing_api::StreamingAeadImpl streaming_aead;
+ StreamingAeadEncryptRequest enc_request;
+ enc_request.set_keyset("bad keyset");
+ enc_request.set_plaintext("Plain text");
+ enc_request.set_associated_data("ad");
+ StreamingAeadEncryptResponse enc_response;
+
+ EXPECT_TRUE(streaming_aead.Encrypt(nullptr, &enc_request,
+ &enc_response).ok());
+ EXPECT_THAT(enc_response.err(), Not(IsEmpty()));
+}
+
+TEST_F(StreamingAeadImplTest, DecryptBadCiphertextFail) {
+ tink_testing_api::StreamingAeadImpl streaming_aead;
+ std::string keyset = ValidKeyset();
+ StreamingAeadDecryptRequest dec_request;
+ dec_request.set_keyset(keyset);
+ dec_request.set_ciphertext("bad ciphertext");
+ dec_request.set_associated_data("ad");
+ StreamingAeadDecryptResponse dec_response;
+
+ EXPECT_TRUE(streaming_aead.Decrypt(nullptr, &dec_request,
+ &dec_response).ok());
+ EXPECT_THAT(dec_response.err(), Not(IsEmpty()));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto
diff --git a/testing/cc/testing_server.cc b/testing/cc/testing_server.cc
new file mode 100644
index 0000000..452b9ed
--- /dev/null
+++ b/testing/cc/testing_server.cc
@@ -0,0 +1,73 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <grpcpp/grpcpp.h>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "tink/config/tink_config.h"
+#include "proto/testing/testing_api.grpc.pb.h"
+#include "aead_impl.h"
+#include "deterministic_aead_impl.h"
+#include "hybrid_impl.h"
+#include "keyset_impl.h"
+#include "mac_impl.h"
+#include "metadata_impl.h"
+#include "signature_impl.h"
+#include "streaming_aead_impl.h"
+
+ABSL_FLAG(int, port, 23456, "the port");
+
+void RunServer() {
+ auto status = crypto::tink::TinkConfig::Register();
+ if (!status.ok()) {
+ std::cout << "TinkConfig::Register() failed: " << status.error_message()
+ << std::endl;
+ return;
+ }
+ const int port = absl::GetFlag(FLAGS_port);
+ std::string server_address = absl::StrCat("[::]:", port);
+
+ tink_testing_api::MetadataImpl metadata;
+ tink_testing_api::KeysetImpl keyset;
+ tink_testing_api::AeadImpl aead;
+ tink_testing_api::DeterministicAeadImpl deterministic_aead;
+ tink_testing_api::HybridImpl hybrid;
+ tink_testing_api::MacImpl mac;
+ tink_testing_api::SignatureImpl signature;
+ tink_testing_api::StreamingAeadImpl streaming_aead;
+
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(
+ server_address, ::grpc::experimental::LocalServerCredentials(LOCAL_TCP));
+
+ builder.RegisterService(&metadata);
+ builder.RegisterService(&keyset);
+ builder.RegisterService(&aead);
+ builder.RegisterService(&deterministic_aead);
+ builder.RegisterService(&hybrid);
+ builder.RegisterService(&mac);
+ builder.RegisterService(&signature);
+ builder.RegisterService(&streaming_aead);
+
+ std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
+ std::cout << "Server listening on " << server_address << std::endl;
+ server->Wait();
+}
+
+int main(int argc, char** argv) {
+ absl::ParseCommandLine(argc, argv);
+ RunServer();
+ return 0;
+}
diff --git a/testing/cross_language/.bazelversion b/testing/cross_language/.bazelversion
new file mode 100644
index 0000000..fd2a018
--- /dev/null
+++ b/testing/cross_language/.bazelversion
@@ -0,0 +1 @@
+3.1.0
diff --git a/testing/cross_language/BUILD.bazel b/testing/cross_language/BUILD.bazel
new file mode 100644
index 0000000..e1ed097
--- /dev/null
+++ b/testing/cross_language/BUILD.bazel
@@ -0,0 +1,128 @@
+load("@pip_deps//:requirements.bzl", "requirement")
+
+package(
+ default_testonly = 1,
+ default_visibility = ["//:__subpackages__"],
+)
+
+licenses(["notice"])
+
+py_test(
+ name = "key_generation_consistency_test",
+ srcs = ["key_generation_consistency_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/proto:common_py_pb2",
+ "@tink_py//tink/proto:ecdsa_py_pb2",
+ "@tink_py//tink/signature",
+ ],
+)
+
+py_test(
+ name = "json_test",
+ srcs = ["json_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ ],
+)
+
+py_test(
+ name = "aead_test",
+ srcs = ["aead_test.py"],
+ deps = [
+ "//util:keyset_builder",
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/proto:tink_py_pb2",
+ ],
+)
+
+py_test(
+ name = "aead_consistency_test",
+ srcs = ["aead_consistency_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/proto:aes_ctr_hmac_aead_py_pb2",
+ "@tink_py//tink/proto:aes_eax_py_pb2",
+ "@tink_py//tink/proto:aes_gcm_py_pb2",
+ "@tink_py//tink/proto:common_py_pb2",
+ "@tink_py//tink/proto:tink_py_pb2",
+ ],
+)
+
+py_test(
+ name = "deterministic_aead_test",
+ srcs = ["deterministic_aead_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/daead",
+ ],
+)
+
+py_test(
+ name = "streaming_aead_test",
+ srcs = ["streaming_aead_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/streaming_aead",
+ ],
+)
+
+py_test(
+ name = "mac_test",
+ srcs = ["mac_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/mac",
+ ],
+)
+
+py_test(
+ name = "signature_test",
+ srcs = ["signature_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/signature",
+ ],
+)
+
+py_test(
+ name = "hybrid_encryption_test",
+ srcs = ["hybrid_encryption_test.py"],
+ deps = [
+ "//util:supported_key_types",
+ "//util:testing_servers",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/hybrid",
+ ],
+)
diff --git a/testing/cross_language/WORKSPACE b/testing/cross_language/WORKSPACE
new file mode 100644
index 0000000..8794129
--- /dev/null
+++ b/testing/cross_language/WORKSPACE
@@ -0,0 +1,99 @@
+workspace(name = "testing_python")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "tink_base",
+ path = "../..",
+)
+
+local_repository(
+ name = "tink_py",
+ path = "../../python",
+)
+
+local_repository(
+ name = "tink_cc",
+ path = "../../cc",
+)
+
+# NOTE: The Python dependencies have to be loaded first, as they rely on a
+# newer version of rules_python.
+load("@tink_py//:tink_py_deps.bzl", "tink_py_deps")
+tink_py_deps()
+
+load("@tink_py//:tink_py_deps_init.bzl", "tink_py_deps_init")
+tink_py_deps_init("tink_py")
+
+load("@tink_py_pip_deps//:requirements.bzl", tink_pip_install = "pip_install")
+tink_pip_install()
+
+load("@tink_base//:tink_base_deps.bzl", "tink_base_deps")
+tink_base_deps()
+
+load("@tink_base//:tink_base_deps_init.bzl", "tink_base_deps_init")
+tink_base_deps_init()
+
+load("@tink_cc//:tink_cc_deps.bzl", "tink_cc_deps")
+tink_cc_deps()
+
+load("@tink_cc//:tink_cc_deps_init.bzl", "tink_cc_deps_init")
+tink_cc_deps_init()
+
+http_archive(
+ name = "rules_python",
+ strip_prefix = "rules_python-94677401bc56ed5d756f50b441a6a5c7f735a6d4",
+ url = "https://github.com/bazelbuild/rules_python/archive/94677401bc56ed5d756f50b441a6a5c7f735a6d4.zip",
+ sha256 = "de39bc4d6605e6d395faf5e07516c64c8d833404ee3eb132b5ff1161f9617dec",
+)
+
+http_archive(
+ name = "rules_proto_grpc",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+)
+
+http_archive(
+ name = "org_python_pypi_portpicker",
+ urls = [
+ "https://pypi.python.org/packages/d9/f4/0188bc07d38b5f9dd192b8329c5e098e3b23552c01a96fd08973dba9e315/portpicker-1.3.1.tar.gz",
+ ],
+ sha256 = "d2cdc776873635ed421315c4d22e63280042456bbfa07397817e687b142b9667",
+ strip_prefix = "portpicker-1.3.1/src",
+ build_file = "portpicker.BUILD.bazel",
+)
+
+load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos")
+rules_proto_grpc_toolchains()
+rules_proto_grpc_repos()
+
+load("@rules_proto_grpc//python:repositories.bzl", rules_proto_grpc_python_repos="python_repos")
+rules_proto_grpc_python_repos()
+
+load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
+
+grpc_deps()
+
+load("@rules_python//python:repositories.bzl", "py_repositories")
+py_repositories()
+
+load("@rules_python//python:pip.bzl", "pip_repositories", "pip3_import")
+pip_repositories()
+
+pip3_import(
+ name = "pip_deps",
+ requirements = "//:requirements.txt",
+)
+
+load("@pip_deps//:requirements.bzl", "pip_install")
+pip_install()
+
+pip3_import(
+ name = "rules_proto_grpc_py3_deps",
+ requirements = "@rules_proto_grpc//python:requirements.txt",
+)
+
+load("@rules_proto_grpc_py3_deps//:requirements.bzl", pip3_install="pip_install")
+pip3_install()
+
diff --git a/testing/cross_language/aead_consistency_test.py b/testing/cross_language/aead_consistency_test.py
new file mode 100644
index 0000000..24a7942
--- /dev/null
+++ b/testing/cross_language/aead_consistency_test.py
@@ -0,0 +1,203 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Cross-language consistency tests for AEAD."""
+
+import itertools
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+import tink
+from tink import aead
+
+from tink.proto import aes_ctr_hmac_aead_pb2
+from tink.proto import aes_eax_pb2
+from tink.proto import aes_gcm_pb2
+from tink.proto import common_pb2
+from tink.proto import tink_pb2
+from util import supported_key_types
+from util import testing_servers
+
+HASH_TYPES = [
+ common_pb2.UNKNOWN_HASH,
+ common_pb2.SHA1,
+ common_pb2.SHA256,
+ common_pb2.SHA384,
+ common_pb2.SHA512
+]
+
+# Test cases that succeed in a language but should fail
+SUCCEEDS_BUT_SHOULD_FAIL = [
+ # TODO(b/159989251)
+ # HMAC with SHA384 is accepted in go, but not in other langs.
+ ('AesCtrHmacAeadKey(16,16,16,16,SHA384,0,0,0)', 'go'),
+]
+
+# Test cases that fail in a language but should succeed
+FAILS_BUT_SHOULD_SUCCEED = [
+]
+
+
+def setUpModule():
+ aead.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
+
+
+def _gen_keyset(
+ type_url: str, value: bytes,
+ key_material_type: tink_pb2.KeyData.KeyMaterialType) -> tink_pb2.Keyset:
+ """Generates a new Keyset."""
+ keyset = tink_pb2.Keyset()
+ key = keyset.key.add()
+ key.key_data.type_url = type_url
+ key.key_data.value = value
+ key.key_data.key_material_type = key_material_type
+ key.status = tink_pb2.ENABLED
+ key.key_id = 42
+ key.output_prefix_type = tink_pb2.TINK
+ keyset.primary_key_id = 42
+ return keyset
+
+
+def _gen_key_value(size: int) -> bytes:
+ """Returns a fixed key_value of a given size."""
+ return bytes(i for i in range(size))
+
+
+def aes_eax_key_test_cases():
+ def _test_case(key_size=16, iv_size=16, key_version=0):
+ key = aes_eax_pb2.AesEaxKey()
+ key.version = key_version
+ key.key_value = _gen_key_value(key_size)
+ key.params.iv_size = iv_size
+ keyset = _gen_keyset(
+ 'type.googleapis.com/google.crypto.tink.AesEaxKey',
+ key.SerializeToString(),
+ tink_pb2.KeyData.SYMMETRIC)
+ return ('AesEaxKey(%d,%d,%d)' % (key_size, iv_size, key_version), keyset)
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ for iv_size in [11, 12, 16, 17, 24, 32]:
+ yield _test_case(key_size=key_size, iv_size=iv_size)
+ yield _test_case(key_version=1)
+
+
+def aes_gcm_key_test_cases():
+ def _test_case(key_size=16, key_version=0):
+ key = aes_gcm_pb2.AesGcmKey()
+ key.version = key_version
+ key.key_value = _gen_key_value(key_size)
+ keyset = _gen_keyset(
+ 'type.googleapis.com/google.crypto.tink.AesGcmKey',
+ key.SerializeToString(),
+ tink_pb2.KeyData.SYMMETRIC)
+ return ('AesGcmKey(%d,%d)' % (key_size, key_version), keyset)
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ yield _test_case(key_size=key_size)
+ yield _test_case(key_version=1)
+
+
+def aes_ctr_hmac_aead_key_test_cases():
+ def _test_case(aes_key_size=16,
+ iv_size=16,
+ hmac_key_size=16,
+ hmac_tag_size=16,
+ hash_type=common_pb2.SHA256,
+ key_version=0,
+ aes_ctr_version=0,
+ hmac_version=0):
+ key = aes_ctr_hmac_aead_pb2.AesCtrHmacAeadKey()
+ key.version = key_version
+ key.aes_ctr_key.version = aes_ctr_version
+ key.aes_ctr_key.params.iv_size = iv_size
+ key.aes_ctr_key.key_value = _gen_key_value(aes_key_size)
+ key.hmac_key.version = hmac_version
+ key.hmac_key.params.tag_size = hmac_tag_size
+ key.hmac_key.params.hash = hash_type
+ key.hmac_key.key_value = _gen_key_value(hmac_key_size)
+ keyset = _gen_keyset(
+ 'type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey',
+ key.SerializeToString(),
+ tink_pb2.KeyData.SYMMETRIC)
+ return ('AesCtrHmacAeadKey(%d,%d,%d,%d,%s,%d,%d,%d)' %
+ (aes_key_size, iv_size, hmac_key_size, hmac_tag_size,
+ common_pb2.HashType.Name(hash_type),
+ key_version, aes_ctr_version, hmac_version), keyset)
+ yield _test_case()
+ for aes_key_size in [15, 16, 24, 32, 64, 96]:
+ for iv_size in [11, 12, 16, 17, 24, 32]:
+ yield _test_case(aes_key_size=aes_key_size, iv_size=iv_size)
+ for hmac_key_size in [15, 16, 24, 32, 64, 96]:
+ for hmac_tag_size in [9, 10, 16, 20, 21, 24, 32, 33, 64, 65]:
+ yield _test_case(hmac_key_size=hmac_key_size,
+ hmac_tag_size=hmac_tag_size)
+ for hash_type in HASH_TYPES:
+ yield _test_case(hash_type=hash_type)
+ yield _test_case(key_version=1)
+ yield _test_case(aes_ctr_version=1)
+ yield _test_case(hmac_version=1)
+
+
+class AeadKeyConsistencyTest(parameterized.TestCase):
+
+ @parameterized.parameters(
+ itertools.chain(aes_eax_key_test_cases(),
+ aes_gcm_key_test_cases(),
+ aes_ctr_hmac_aead_key_test_cases()))
+ def test_keyset_validation_consistency(self, name, keyset):
+ supported_langs = supported_key_types.SUPPORTED_LANGUAGES_PER_TYPE_URL[
+ keyset.key[0].key_data.type_url]
+ supported_aeads = [
+ testing_servers.aead(lang, keyset.SerializeToString())
+ for lang in supported_langs
+ ]
+ plaintext = b'plaintext'
+ associated_data = b'associated_data'
+ failures = 0
+ ciphertexts = {}
+ results = {}
+ for p in supported_aeads:
+ try:
+ ciphertexts[p.lang] = p.encrypt(plaintext, associated_data)
+ if (name, p.lang) in SUCCEEDS_BUT_SHOULD_FAIL:
+ failures += 1
+ del ciphertexts[p.lang]
+ if (name, p.lang) in FAILS_BUT_SHOULD_SUCCEED:
+ self.fail('(%s, %s) succeeded, but is in FAILS_BUT_SHOULD_SUCCEED' %
+ (name, p.lang))
+ results[p.lang] = 'success'
+ except tink.TinkError as e:
+ if (name, p.lang) not in FAILS_BUT_SHOULD_SUCCEED:
+ failures += 1
+ if (name, p.lang) in SUCCEEDS_BUT_SHOULD_FAIL:
+ self.fail(
+ '(%s, %s) is in SUCCEEDS_BUT_SHOULD_FAIL, but failed with %s' %
+ (name, p.lang, e))
+ results[p.lang] = e
+ # Test that either all supported langs accept the key, or all reject.
+ if failures not in [0, len(supported_langs)]:
+ self.fail('encryption for key %s is inconsistent: %s' %
+ (name, results))
+ # Test all generated ciphertexts can be decypted.
+ for enc_lang, ciphertext in ciphertexts.items():
+ dec_aead = supported_aeads[0]
+ output = dec_aead.decrypt(ciphertext, associated_data)
+ if output != plaintext:
+ self.fail('ciphertext encrypted with key %s in lang %s could not be'
+ 'decrypted in lang %s.' % (name, enc_lang, dec_aead.lang))
+
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/testing/cross_language/aead_test.py b/testing/cross_language/aead_test.py
new file mode 100644
index 0000000..f1dd417
--- /dev/null
+++ b/testing/cross_language/aead_test.py
@@ -0,0 +1,138 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Cross-language tests for the Aead primitive."""
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+import tink
+from tink import aead
+
+from tink.proto import tink_pb2
+from util import keyset_builder
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE['aead']
+
+
+def key_rotation_test_cases():
+ for enc_lang in SUPPORTED_LANGUAGES:
+ for dec_lang in SUPPORTED_LANGUAGES:
+ for prefix in [tink_pb2.RAW, tink_pb2.TINK]:
+ old_key_tmpl = aead.aead_key_templates.create_aes_gcm_key_template(16)
+ old_key_tmpl.output_prefix_type = prefix
+ new_key_tmpl = aead.aead_key_templates.AES128_CTR_HMAC_SHA256
+ yield (enc_lang, dec_lang, old_key_tmpl, new_key_tmpl)
+
+
+def setUpModule():
+ aead.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
+
+
+class AeadPythonTest(parameterized.TestCase):
+
+ @parameterized.parameters(
+ supported_key_types.test_cases(supported_key_types.AEAD_KEY_TYPES))
+ def test_encrypt_decrypt(self, key_template_name, supported_langs):
+ key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
+ # use java to generate keys, as it supports all key types.
+ keyset = testing_servers.new_keyset('java', key_template)
+ supported_aeads = [
+ testing_servers.aead(lang, keyset) for lang in supported_langs
+ ]
+ unsupported_aeads = [
+ testing_servers.aead(lang, keyset)
+ for lang in SUPPORTED_LANGUAGES
+ if lang not in supported_langs
+ ]
+ for p in supported_aeads:
+ plaintext = (
+ b'This is some plaintext message to be encrypted using key_template '
+ b'%s using %s for encryption.'
+ % (key_template_name.encode('utf8'), p.lang.encode('utf8')))
+ associated_data = (
+ b'Some associated data for %s using %s for encryption.' %
+ (key_template_name.encode('utf8'), p.lang.encode('utf8')))
+ ciphertext = p.encrypt(plaintext, associated_data)
+ for p2 in supported_aeads:
+ output = p2.decrypt(ciphertext, associated_data)
+ self.assertEqual(output, plaintext)
+ for p2 in unsupported_aeads:
+ with self.assertRaises(tink.TinkError):
+ p2.decrypt(ciphertext, associated_data)
+ for p in unsupported_aeads:
+ with self.assertRaises(tink.TinkError):
+ p.encrypt(b'plaintext', b'associated_data')
+
+ @parameterized.parameters(key_rotation_test_cases())
+ def test_key_rotation(self, enc_lang, dec_lang, old_key_tmpl, new_key_tmpl):
+ # Do a key rotation from an old key generated from old_key_tmpl to a new
+ # key generated from new_key_tmpl. Encryption and decryption are done
+ # in languages enc_lang and dec_lang.
+ builder = keyset_builder.new_keyset_builder()
+ older_key_id = builder.add_new_key(old_key_tmpl)
+ builder.set_primary_key(older_key_id)
+ enc_aead1 = testing_servers.aead(enc_lang, builder.keyset())
+ dec_aead1 = testing_servers.aead(dec_lang, builder.keyset())
+ newer_key_id = builder.add_new_key(new_key_tmpl)
+ enc_aead2 = testing_servers.aead(enc_lang, builder.keyset())
+ dec_aead2 = testing_servers.aead(dec_lang, builder.keyset())
+
+ builder.set_primary_key(newer_key_id)
+ enc_aead3 = testing_servers.aead(enc_lang, builder.keyset())
+ dec_aead3 = testing_servers.aead(dec_lang, builder.keyset())
+
+ builder.disable_key(older_key_id)
+ enc_aead4 = testing_servers.aead(enc_lang, builder.keyset())
+ dec_aead4 = testing_servers.aead(dec_lang, builder.keyset())
+
+ self.assertNotEqual(older_key_id, newer_key_id)
+ # 1 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4.
+ ciphertext1 = enc_aead1.encrypt(b'plaintext', b'ad')
+ self.assertEqual(dec_aead1.decrypt(ciphertext1, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead2.decrypt(ciphertext1, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead3.decrypt(ciphertext1, b'ad'), b'plaintext')
+ with self.assertRaises(tink.TinkError):
+ _ = dec_aead4.decrypt(ciphertext1, b'ad')
+
+ # 2 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4.
+ ciphertext2 = enc_aead2.encrypt(b'plaintext', b'ad')
+ self.assertEqual(dec_aead1.decrypt(ciphertext2, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead2.decrypt(ciphertext2, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead3.decrypt(ciphertext2, b'ad'), b'plaintext')
+ with self.assertRaises(tink.TinkError):
+ _ = dec_aead4.decrypt(ciphertext2, b'ad')
+
+ # 3 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1.
+ ciphertext3 = enc_aead3.encrypt(b'plaintext', b'ad')
+ with self.assertRaises(tink.TinkError):
+ _ = dec_aead1.decrypt(ciphertext3, b'ad')
+ self.assertEqual(dec_aead2.decrypt(ciphertext3, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead3.decrypt(ciphertext3, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead4.decrypt(ciphertext3, b'ad'), b'plaintext')
+
+ # 4 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1.
+ ciphertext4 = enc_aead4.encrypt(b'plaintext', b'ad')
+ with self.assertRaises(tink.TinkError):
+ _ = dec_aead1.decrypt(ciphertext4, b'ad')
+ self.assertEqual(dec_aead2.decrypt(ciphertext4, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead3.decrypt(ciphertext4, b'ad'), b'plaintext')
+ self.assertEqual(dec_aead4.decrypt(ciphertext4, b'ad'), b'plaintext')
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/tools/testing/cross_language/deterministic_aead_test.py b/testing/cross_language/deterministic_aead_test.py
similarity index 83%
rename from tools/testing/cross_language/deterministic_aead_test.py
rename to testing/cross_language/deterministic_aead_test.py
index 90aa6a9..9d3d29f 100644
--- a/tools/testing/cross_language/deterministic_aead_test.py
+++ b/testing/cross_language/deterministic_aead_test.py
@@ -16,13 +16,19 @@
import tink
from tink import daead
-from tools.testing import supported_key_types
-from tools.testing.cross_language.util import cli_daead
-from tools.testing.cross_language.util import keyset_manager
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE['daead']
def setUpModule():
daead.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
class DeterministicAeadTest(parameterized.TestCase):
@@ -31,15 +37,15 @@
supported_key_types.test_cases(supported_key_types.DAEAD_KEY_TYPES))
def test_encrypt_decrypt(self, key_template_name, supported_langs):
key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
- keyset_handle = keyset_manager.new_keyset_handle(key_template)
+ keyset = testing_servers.new_keyset('java', key_template)
supported_daeads = [
- cli_daead.CliDeterministicAead(lang, keyset_handle)
+ testing_servers.deterministic_aead(lang, keyset)
for lang in supported_langs
]
self.assertNotEmpty(supported_daeads)
unsupported_daeads = [
- cli_daead.CliDeterministicAead(lang, keyset_handle)
- for lang in cli_daead.LANGUAGES
+ testing_servers.deterministic_aead(lang, keyset)
+ for lang in SUPPORTED_LANGUAGES
if lang not in supported_langs
]
plaintext = (
diff --git a/testing/cross_language/external/portpicker.BUILD.bazel b/testing/cross_language/external/portpicker.BUILD.bazel
new file mode 100644
index 0000000..57e2ec3
--- /dev/null
+++ b/testing/cross_language/external/portpicker.BUILD.bazel
@@ -0,0 +1,13 @@
+# Description:
+# Import of portpicker library.
+
+licenses(["notice"])
+
+exports_files(["LICENSE"])
+
+py_library(
+ name = "portpicker",
+ srcs = glob(["*.py"]),
+ srcs_version = "PY2AND3",
+ visibility = ["//visibility:public"],
+)
diff --git a/tools/testing/cross_language/hybrid_encryption_test.py b/testing/cross_language/hybrid_encryption_test.py
similarity index 76%
rename from tools/testing/cross_language/hybrid_encryption_test.py
rename to testing/cross_language/hybrid_encryption_test.py
index 36476bc..71cfc10 100644
--- a/tools/testing/cross_language/hybrid_encryption_test.py
+++ b/testing/cross_language/hybrid_encryption_test.py
@@ -17,13 +17,19 @@
import tink
from tink import hybrid
-from tools.testing import supported_key_types
-from tools.testing.cross_language.util import cli_hybrid
-from tools.testing.cross_language.util import keyset_manager
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE['hybrid']
def setUpModule():
hybrid.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
class HybridEncryptionTest(parameterized.TestCase):
@@ -33,24 +39,24 @@
supported_key_types.HYBRID_PRIVATE_KEY_TYPES))
def test_encrypt_decrypt(self, key_template_name, supported_langs):
key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
- private_handle = keyset_manager.new_keyset_handle(key_template)
+ private_keyset = testing_servers.new_keyset('java', key_template)
supported_decs = [
- cli_hybrid.CliHybridDecrypt(lang, private_handle)
+ testing_servers.hybrid_decrypt(lang, private_keyset)
for lang in supported_langs
]
unsupported_decs = [
- cli_hybrid.CliHybridDecrypt(lang, private_handle)
- for lang in cli_hybrid.LANGUAGES
+ testing_servers.hybrid_decrypt(lang, private_keyset)
+ for lang in SUPPORTED_LANGUAGES
if lang not in supported_langs
]
- public_handle = private_handle.public_keyset_handle()
+ public_keyset = testing_servers.public_keyset('java', private_keyset)
supported_encs = [
- cli_hybrid.CliHybridEncrypt(lang, public_handle)
+ testing_servers.hybrid_encrypt(lang, public_keyset)
for lang in supported_langs
]
unsupported_encs = [
- cli_hybrid.CliHybridEncrypt(lang, public_handle)
- for lang in cli_hybrid.LANGUAGES
+ testing_servers.hybrid_encrypt(lang, public_keyset)
+ for lang in testing_servers.LANGUAGES
if lang not in supported_langs
]
for enc in supported_encs:
diff --git a/testing/cross_language/json_test.py b/testing/cross_language/json_test.py
new file mode 100644
index 0000000..d755253
--- /dev/null
+++ b/testing/cross_language/json_test.py
@@ -0,0 +1,95 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Cross-language tests for JSON serialization."""
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+from tink.proto import tink_pb2
+from util import supported_key_types
+from util import testing_servers
+
+
+def setUpModule():
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
+
+
+def _keyset_proto(keyset: bytes) -> tink_pb2.Keyset:
+ keyset_proto = tink_pb2.Keyset()
+ keyset_proto.ParseFromString(keyset)
+ # We sort the keys, since we want keysets to be considered equal even if the
+ # keys are in different order.
+ keyset_proto.key.sort(key=lambda k: k.key_id)
+ return keyset_proto
+
+
+def _is_equal_keyset(keyset1: bytes, keyset2: bytes) -> bool:
+ """Checks if two keyset are equal, and have the exact same keydata.value."""
+ # Keydata.value are serialized protos. This serialization is usually not
+ # deterministic, as it is a unsorted list of key value pairs.
+ # But since JSON serialization does not change keyset.value, we can simply
+ # require these values to be exactly the same in this test. In other tests,
+ # this might be too strict.
+ return _keyset_proto(keyset1) == _keyset_proto(keyset2)
+
+
+class JsonTest(parameterized.TestCase):
+
+ def test_is_equal_keyset(self):
+ keyset1 = tink_pb2.Keyset()
+ key11 = keyset1.key.add()
+ key11.key_id = 21
+ key12 = keyset1.key.add()
+ key12.key_id = 42
+ keyset2 = tink_pb2.Keyset()
+ key21 = keyset2.key.add()
+ key21.key_id = 42
+ key22 = keyset2.key.add()
+ key22.key_id = 21
+ self.assertTrue(_is_equal_keyset(keyset1.SerializeToString(),
+ keyset2.SerializeToString()))
+
+ def test_is_not_equal_keyset(self):
+ keyset1 = tink_pb2.Keyset()
+ key11 = keyset1.key.add()
+ key11.key_id = 21
+ key12 = keyset1.key.add()
+ key12.key_id = 42
+ keyset2 = tink_pb2.Keyset()
+ key3 = keyset2.key.add()
+ key3.key_id = 21
+ self.assertFalse(_is_equal_keyset(keyset1.SerializeToString(),
+ keyset2.SerializeToString()))
+
+ def assertEqualKeyset(self, keyset1: bytes, keyset2: bytes):
+ if not _is_equal_keyset(keyset1, keyset2):
+ self.fail('these keysets are not equal: \n%s\n \n%s\n'
+ % (_keyset_proto(keyset1), _keyset_proto(keyset2)))
+
+ @parameterized.parameters(
+ supported_key_types.test_cases(supported_key_types.ALL_KEY_TYPES))
+ def test_to_from_json(self, key_template_name, supported_langs):
+ key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
+ keyset = testing_servers.new_keyset('java', key_template)
+ for to_lang in supported_langs:
+ json_keyset = testing_servers.keyset_to_json(to_lang, keyset)
+ for from_lang in supported_langs:
+ keyset2 = testing_servers.keyset_from_json(from_lang, json_keyset)
+ self.assertEqualKeyset(keyset, keyset2)
+
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/testing/cross_language/key_generation_consistency_test.py b/testing/cross_language/key_generation_consistency_test.py
new file mode 100644
index 0000000..6f75bc1
--- /dev/null
+++ b/testing/cross_language/key_generation_consistency_test.py
@@ -0,0 +1,339 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests for tink.testing.cross_language.key_generation_consistency."""
+
+import itertools
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+import tink
+from tink import aead
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature
+
+from tink.proto import common_pb2
+from tink.proto import ecdsa_pb2
+from util import supported_key_types
+from util import testing_servers
+
+TYPE_URL_TO_SUPPORTED_LANGUAGES = {
+ 'type.googleapis.com/google.crypto.tink.' + key_type: langs
+ for key_type, langs in supported_key_types.SUPPORTED_LANGUAGES.items()
+}
+
+# Test cases that succeed in a language but should fail
+SUCCEEDS_BUT_SHOULD_FAIL = [
+ # TODO(b/159989251)
+ # HMAC with SHA384 is accepted in go, but not in other langs.
+ ('HmacKey(32,10,SHA384)', 'go'),
+ ('HmacKey(32,16,SHA384)', 'go'),
+ ('HmacKey(32,20,SHA384)', 'go'),
+ ('HmacKey(32,21,SHA384)', 'go'),
+ ('HmacKey(32,24,SHA384)', 'go'),
+ ('HmacKey(32,32,SHA384)', 'go'),
+ ('HmacKey(32,33,SHA384)', 'go'),
+ # TODO(b/160130470): In CC and Python Hybrid templates are not checked for
+ # valid AEAD params. (These params *are* checked when the key is used.)
+ ('EciesAeadHkdfPrivateKey(NIST_P256,UNCOMPRESSED,SHA256,AesEaxKey(15,11))',
+ 'cc'),
+ ('EciesAeadHkdfPrivateKey(NIST_P256,UNCOMPRESSED,SHA256,AesEaxKey(15,11))',
+ 'python'),
+]
+
+# Test cases that fail in a language but should succeed
+FAILS_BUT_SHOULD_SUCCEED = [
+ # TODO(b/160134058) Java and Go do not accept templates with CURVE25519.
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA1,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA1,AesGcmKey(16))',
+ 'go'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA256,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA256,AesGcmKey(16))',
+ 'go'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA384,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA384,AesGcmKey(16))',
+ 'go'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA512,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(CURVE25519,UNCOMPRESSED,SHA512,AesGcmKey(16))',
+ 'go'),
+ # TODO(b/160132617) Java does not accept templates with hash type SHA384.
+ ('EciesAeadHkdfPrivateKey(NIST_P256,UNCOMPRESSED,SHA384,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(NIST_P384,UNCOMPRESSED,SHA384,AesGcmKey(16))',
+ 'java'),
+ ('EciesAeadHkdfPrivateKey(NIST_P521,UNCOMPRESSED,SHA384,AesGcmKey(16))',
+ 'java'),
+ # TODO(b/140101381) CC does not support Ecdsa with NIST_P384 and SHA384.
+ ('EcdsaPrivateKey(SHA384,NIST_P384,IEEE_P1363)', 'cc'),
+ ('EcdsaPrivateKey(SHA384,NIST_P384,IEEE_P1363)', 'python'),
+ ('EcdsaPrivateKey(SHA384,NIST_P384,DER)', 'cc'),
+ ('EcdsaPrivateKey(SHA384,NIST_P384,DER)', 'python'),
+]
+
+HASH_TYPES = [
+ common_pb2.UNKNOWN_HASH,
+ common_pb2.SHA1,
+ common_pb2.SHA256,
+ common_pb2.SHA384,
+ common_pb2.SHA512
+]
+
+CURVE_TYPES = [
+ common_pb2.UNKNOWN_CURVE,
+ common_pb2.NIST_P256,
+ common_pb2.NIST_P384,
+ common_pb2.NIST_P521,
+ common_pb2.CURVE25519
+]
+
+EC_POINT_FORMATS = [
+ common_pb2.UNKNOWN_FORMAT,
+ common_pb2.UNCOMPRESSED,
+ common_pb2.COMPRESSED,
+ common_pb2.DO_NOT_USE_CRUNCHY_UNCOMPRESSED
+]
+
+SIGNATURE_ENCODINGS = [
+ ecdsa_pb2.UNKNOWN_ENCODING,
+ ecdsa_pb2.IEEE_P1363,
+ ecdsa_pb2.DER
+]
+
+
+def aes_eax_test_cases():
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ for iv_size in [11, 12, 16, 17, 24, 32]:
+ yield ('AesEaxKey(%d,%d)' % (key_size, iv_size),
+ aead.aead_key_templates.create_aes_eax_key_template(
+ key_size, iv_size))
+
+
+def aes_gcm_test_cases():
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ yield ('AesGcmKey(%d)' % key_size,
+ aead.aead_key_templates.create_aes_gcm_key_template(key_size))
+
+
+def aes_ctr_hmac_aead_test_cases():
+ def _test_case(aes_key_size=16, iv_size=16, hmac_key_size=16,
+ tag_size=16, hash_type=common_pb2.SHA256):
+ return ('AesCtrHmacAeadKey(%d,%d,%d,%d,%s)' %
+ (aes_key_size, iv_size, hmac_key_size, tag_size,
+ common_pb2.HashType.Name(hash_type)),
+ aead.aead_key_templates.create_aes_ctr_hmac_aead_key_template(
+ aes_key_size=aes_key_size,
+ iv_size=iv_size,
+ hmac_key_size=hmac_key_size,
+ tag_size=tag_size,
+ hash_type=hash_type))
+ for aes_key_size in [15, 16, 24, 32, 64, 96]:
+ for iv_size in [11, 12, 16, 17, 24, 32]:
+ yield _test_case(aes_key_size=aes_key_size, iv_size=iv_size)
+ for hmac_key_size in [15, 16, 24, 32, 64, 96]:
+ for tag_size in [9, 10, 16, 20, 21, 24, 32, 33, 64, 65]:
+ for hash_type in HASH_TYPES:
+ yield _test_case(hmac_key_size=hmac_key_size, tag_size=tag_size,
+ hash_type=hash_type)
+
+
+def hmac_test_cases():
+ def _test_case(key_size=32, tag_size=16, hash_type=common_pb2.SHA256):
+ return ('HmacKey(%d,%d,%s)' % (key_size, tag_size,
+ common_pb2.HashType.Name(hash_type)),
+ mac.mac_key_templates.create_hmac_key_template(
+ key_size, tag_size, hash_type))
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ yield _test_case(key_size=key_size)
+ for tag_size in [9, 10, 16, 20, 21, 24, 32, 33, 64, 65]:
+ for hash_type in HASH_TYPES:
+ yield _test_case(tag_size=tag_size, hash_type=hash_type)
+
+
+def aes_siv_test_cases():
+ for key_size in [15, 16, 24, 32, 64, 96]:
+ yield ('AesSivKey(%d)' % key_size,
+ daead.deterministic_aead_key_templates.create_aes_siv_key_template(
+ key_size))
+
+
+def ecies_aead_hkdf_test_cases():
+ for curve_type in CURVE_TYPES:
+ for hash_type in HASH_TYPES:
+ ec_point_format = common_pb2.UNCOMPRESSED
+ dem_key_template = aead.aead_key_templates.AES128_GCM
+ yield ('EciesAeadHkdfPrivateKey(%s,%s,%s,AesGcmKey(16))' %
+ (common_pb2.EllipticCurveType.Name(curve_type),
+ common_pb2.EcPointFormat.Name(ec_point_format),
+ common_pb2.HashType.Name(hash_type)),
+ hybrid.hybrid_key_templates.create_ecies_aead_hkdf_key_template(
+ curve_type, ec_point_format, hash_type, dem_key_template))
+ for ec_point_format in EC_POINT_FORMATS:
+ curve_type = common_pb2.NIST_P256
+ hash_type = common_pb2.SHA256
+ dem_key_template = aead.aead_key_templates.AES128_GCM
+ yield ('EciesAeadHkdfPrivateKey(%s,%s,%s,AesGcmKey(16))' %
+ (common_pb2.EllipticCurveType.Name(curve_type),
+ common_pb2.EcPointFormat.Name(ec_point_format),
+ common_pb2.HashType.Name(hash_type)),
+ hybrid.hybrid_key_templates.create_ecies_aead_hkdf_key_template(
+ curve_type, ec_point_format, hash_type, dem_key_template))
+ curve_type = common_pb2.NIST_P256
+ ec_point_format = common_pb2.UNCOMPRESSED
+ hash_type = common_pb2.SHA256
+ # Use invalid AEAD key template as DEM
+ # TODO(juerg): Once b/160130470 is fixed, increase test coverage to all
+ # aead templates.
+ dem_key_template = aead.aead_key_templates.create_aes_eax_key_template(15, 11)
+ yield ('EciesAeadHkdfPrivateKey(%s,%s,%s,AesEaxKey(15,11))' %
+ (common_pb2.EllipticCurveType.Name(curve_type),
+ common_pb2.EcPointFormat.Name(ec_point_format),
+ common_pb2.HashType.Name(hash_type)),
+ hybrid.hybrid_key_templates.create_ecies_aead_hkdf_key_template(
+ curve_type, ec_point_format, hash_type, dem_key_template))
+
+
+def ecdsa_test_cases():
+ for hash_type in HASH_TYPES:
+ for curve_type in CURVE_TYPES:
+ for signature_encoding in SIGNATURE_ENCODINGS:
+ yield ('EcdsaPrivateKey(%s,%s,%s)' %
+ (common_pb2.HashType.Name(hash_type),
+ common_pb2.EllipticCurveType.Name(curve_type),
+ ecdsa_pb2.EcdsaSignatureEncoding.Name(signature_encoding)),
+ signature.signature_key_templates.create_ecdsa_key_template(
+ hash_type, curve_type, signature_encoding))
+
+
+def rsa_ssa_pkcs1_test_cases():
+ gen = signature.signature_key_templates.create_rsa_ssa_pkcs1_key_template
+ for hash_type in HASH_TYPES:
+ modulus_size = 2048
+ public_exponent = 65537
+ yield ('RsaSsaPkcs1PrivateKey(%s,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type), modulus_size,
+ public_exponent),
+ gen(hash_type, modulus_size, public_exponent))
+ for modulus_size in [0, 2000, 3072, 4096]:
+ hash_type = common_pb2.SHA256
+ public_exponent = 65537
+ yield ('RsaSsaPkcs1PrivateKey(%s,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type), modulus_size,
+ public_exponent),
+ gen(hash_type, modulus_size, public_exponent))
+ # TODO(b/160214390): Add tests for public_exponent, once this bug is resolved.
+
+
+def rsa_ssa_pss_test_cases():
+ gen = signature.signature_key_templates.create_rsa_ssa_pss_key_template
+ for hash_type in HASH_TYPES:
+ salt_length = 32
+ modulus_size = 2048
+ public_exponent = 65537
+ yield ('RsaSsaPssPrivateKey(%s,%s,%d,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type),
+ common_pb2.HashType.Name(hash_type), salt_length, modulus_size,
+ public_exponent),
+ gen(hash_type, hash_type, salt_length, modulus_size,
+ public_exponent))
+ for salt_length in [-3, 0, 1, 16, 64]:
+ hash_type = common_pb2.SHA256
+ modulus_size = 2048
+ public_exponent = 65537
+ yield ('RsaSsaPssPrivateKey(%s,%s,%d,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type),
+ common_pb2.HashType.Name(hash_type), salt_length, modulus_size,
+ public_exponent),
+ gen(hash_type, hash_type, salt_length, modulus_size,
+ public_exponent))
+ for modulus_size in [0, 2000, 3072, 4096]:
+ hash_type = common_pb2.SHA256
+ salt_length = 32
+ public_exponent = 65537
+ yield ('RsaSsaPssPrivateKey(%s,%s,%d,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type),
+ common_pb2.HashType.Name(hash_type), salt_length, modulus_size,
+ public_exponent),
+ gen(hash_type, hash_type, salt_length, modulus_size,
+ public_exponent))
+ hash_type1 = common_pb2.SHA256
+ hash_type2 = common_pb2.SHA512
+ salt_length = 32
+ modulus_size = 2048
+ public_exponent = 65537
+ yield ('RsaSsaPssPrivateKey(%s,%s,%d,%d,%d)' %
+ (common_pb2.HashType.Name(hash_type1),
+ common_pb2.HashType.Name(hash_type2), salt_length, modulus_size,
+ public_exponent),
+ gen(hash_type1, hash_type2, salt_length, modulus_size,
+ public_exponent))
+
+
+def setUpModule():
+ aead.register()
+ daead.register()
+ mac.register()
+ hybrid.register()
+ signature.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
+
+
+class KeyGenerationConsistencyTest(parameterized.TestCase):
+
+ @parameterized.parameters(
+ itertools.chain(aes_eax_test_cases(),
+ aes_gcm_test_cases(),
+ aes_ctr_hmac_aead_test_cases(),
+ hmac_test_cases(),
+ aes_siv_test_cases(),
+ ecies_aead_hkdf_test_cases(),
+ ecdsa_test_cases(),
+ rsa_ssa_pkcs1_test_cases(),
+ rsa_ssa_pss_test_cases()))
+ def test_key_generation_consistency(self, name, template):
+ supported_langs = TYPE_URL_TO_SUPPORTED_LANGUAGES[template.type_url]
+ failures = 0
+ results = {}
+ for lang in supported_langs:
+ try:
+ _ = testing_servers.new_keyset(lang, template)
+ if (name, lang) in SUCCEEDS_BUT_SHOULD_FAIL:
+ failures += 1
+ if (name, lang) in FAILS_BUT_SHOULD_SUCCEED:
+ self.fail('(%s, %s) succeeded, but is in FAILS_BUT_SHOULD_SUCCEED' %
+ (name, lang))
+ results[lang] = 'success'
+ except tink.TinkError as e:
+ if (name, lang) not in FAILS_BUT_SHOULD_SUCCEED:
+ failures += 1
+ if (name, lang) in SUCCEEDS_BUT_SHOULD_FAIL:
+ self.fail(
+ '(%s, %s) is in SUCCEEDS_BUT_SHOULD_FAIL, but failed with %s' %
+ (name, lang, e))
+ results[lang] = e
+ # Test that either all supported langs accept the template, or all reject.
+ if failures not in [0, len(supported_langs)]:
+ self.fail('key generation for template %s is inconsistent: %s' %
+ (name, results))
+
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/tools/testing/cross_language/mac_test.py b/testing/cross_language/mac_test.py
similarity index 79%
rename from tools/testing/cross_language/mac_test.py
rename to testing/cross_language/mac_test.py
index 8a38b43..785cd53 100644
--- a/tools/testing/cross_language/mac_test.py
+++ b/testing/cross_language/mac_test.py
@@ -17,13 +17,19 @@
import tink
from tink import mac
-from tools.testing import supported_key_types
-from tools.testing.cross_language.util import cli_mac
-from tools.testing.cross_language.util import keyset_manager
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE['mac']
def setUpModule():
mac.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
class MacTest(parameterized.TestCase):
@@ -32,14 +38,13 @@
supported_key_types.test_cases(supported_key_types.MAC_KEY_TYPES))
def test_encrypt_decrypt(self, key_template_name, supported_langs):
key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
- keyset_handle = keyset_manager.new_keyset_handle(key_template)
+ keyset = testing_servers.new_keyset('java', key_template)
supported_macs = [
- cli_mac.CliMac(lang, keyset_handle)
- for lang in supported_langs
+ testing_servers.mac(lang, keyset) for lang in supported_langs
]
unsupported_macs = [
- cli_mac.CliMac(lang, keyset_handle)
- for lang in cli_mac.LANGUAGES
+ testing_servers.mac(lang, keyset)
+ for lang in SUPPORTED_LANGUAGES
if lang not in supported_langs
]
for p in supported_macs:
diff --git a/testing/cross_language/requirements.txt b/testing/cross_language/requirements.txt
new file mode 100644
index 0000000..b998a06
--- /dev/null
+++ b/testing/cross_language/requirements.txt
@@ -0,0 +1 @@
+absl-py
diff --git a/tools/testing/cross_language/signature_test.py b/testing/cross_language/signature_test.py
similarity index 72%
rename from tools/testing/cross_language/signature_test.py
rename to testing/cross_language/signature_test.py
index c01e502..3c508e8 100644
--- a/tools/testing/cross_language/signature_test.py
+++ b/testing/cross_language/signature_test.py
@@ -17,13 +17,20 @@
import tink
from tink import signature
-from tools.testing import supported_key_types
-from tools.testing.cross_language.util import cli_signature
-from tools.testing.cross_language.util import keyset_manager
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = (testing_servers
+ .SUPPORTED_LANGUAGES_BY_PRIMITIVE['signature'])
def setUpModule():
signature.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
class SignaturePythonTest(parameterized.TestCase):
@@ -32,24 +39,24 @@
supported_key_types.test_cases(supported_key_types.SIGNATURE_KEY_TYPES))
def test_encrypt_decrypt(self, key_template_name, supported_langs):
key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
- private_handle = keyset_manager.new_keyset_handle(key_template)
+ private_keyset = testing_servers.new_keyset('java', key_template)
supported_signers = [
- cli_signature.CliPublicKeySign(lang, private_handle)
+ testing_servers.public_key_sign(lang, private_keyset)
for lang in supported_langs
]
unsupported_signers = [
- cli_signature.CliPublicKeySign(lang, private_handle)
- for lang in cli_signature.LANGUAGES
+ testing_servers.public_key_sign(lang, private_keyset)
+ for lang in SUPPORTED_LANGUAGES
if lang not in supported_langs
]
- public_handle = private_handle.public_keyset_handle()
+ public_keyset = testing_servers.public_keyset('java', private_keyset)
supported_verifiers = [
- cli_signature.CliPublicKeyVerify(lang, public_handle)
+ testing_servers.public_key_verify(lang, public_keyset)
for lang in supported_langs
]
unsupported_verifiers = [
- cli_signature.CliPublicKeyVerify(lang, public_handle)
- for lang in cli_signature.LANGUAGES
+ testing_servers.public_key_verify(lang, public_keyset)
+ for lang in testing_servers.LANGUAGES
if lang not in supported_langs
]
for signer in supported_signers:
diff --git a/testing/cross_language/streaming_aead_test.py b/testing/cross_language/streaming_aead_test.py
new file mode 100644
index 0000000..befe0ba
--- /dev/null
+++ b/testing/cross_language/streaming_aead_test.py
@@ -0,0 +1,84 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Cross-language tests for the StreamingAead primitive."""
+
+import io
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+import tink
+from tink import streaming_aead
+
+from util import supported_key_types
+from util import testing_servers
+
+SUPPORTED_LANGUAGES = (testing_servers
+ .SUPPORTED_LANGUAGES_BY_PRIMITIVE['streaming_aead'])
+
+
+def setUpModule():
+ streaming_aead.register()
+ testing_servers.start()
+
+
+def tearDownModule():
+ testing_servers.stop()
+
+
+class StreamingAeadPythonTest(parameterized.TestCase):
+
+ @parameterized.parameters(
+ supported_key_types.test_cases(
+ supported_key_types.STREAMING_AEAD_KEY_TYPES))
+ def test_encrypt_decrypt(self, key_template_name, supported_langs):
+ key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
+ # Use java to generate keys, as it supports all key types.
+ keyset = testing_servers.new_keyset('java', key_template)
+ supported_streaming_aeads = [
+ testing_servers.streaming_aead(lang, keyset) for lang in supported_langs
+ ]
+ unsupported_streaming_aeads = [
+ testing_servers.streaming_aead(lang, keyset)
+ for lang in SUPPORTED_LANGUAGES
+ if lang not in supported_langs
+ ]
+ for p in supported_streaming_aeads:
+ plaintext = (
+ b'This is some plaintext message to be encrypted using key_template '
+ b'%s using %s for encryption.'
+ % (key_template_name.encode('utf8'), p.lang.encode('utf8')))
+ associated_data = (
+ b'Some associated data for %s using %s for encryption.' %
+ (key_template_name.encode('utf8'), p.lang.encode('utf8')))
+ plaintext_stream = io.BytesIO(plaintext)
+ ciphertext_result_stream = p.new_encrypting_stream(
+ plaintext_stream, associated_data)
+ ciphertext = ciphertext_result_stream.read()
+ for p2 in supported_streaming_aeads:
+ ciphertext_stream = io.BytesIO(ciphertext)
+ decrypted_stream = p2.new_decrypting_stream(
+ ciphertext_stream, associated_data)
+ self.assertEqual(decrypted_stream.read(), plaintext)
+ for p2 in unsupported_streaming_aeads:
+ with self.assertRaises(tink.TinkError):
+ ciphertext_stream = io.BytesIO(ciphertext)
+ decrypted_stream = p2.new_decrypting_stream(
+ ciphertext_stream, associated_data)
+ for p in unsupported_streaming_aeads:
+ with self.assertRaises(tink.TinkError):
+ plaintext_stream = io.BytesIO(b'plaintext')
+ ciphertext_result_stream = p.new_encrypting_stream(
+ plaintext_stream, b'associated_data')
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/testing/cross_language/util/BUILD.bazel b/testing/cross_language/util/BUILD.bazel
new file mode 100644
index 0000000..a83cd24
--- /dev/null
+++ b/testing/cross_language/util/BUILD.bazel
@@ -0,0 +1,127 @@
+load("@rules_proto_grpc//python:defs.bzl", "python_grpc_library")
+load("@rules_python//python:defs.bzl", "py_library")
+load("@pip_deps//:requirements.bzl", "requirement")
+
+package(
+ default_testonly = 1,
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"])
+
+python_grpc_library(
+ name = "testing_api_python_library",
+ deps = ["@tink_base//proto/testing:testing_api_proto"],
+)
+
+py_library(
+ name = "supported_key_types",
+ testonly = 1,
+ srcs = ["supported_key_types.py"],
+ deps = [
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/proto:tink_py_pb2",
+ "@tink_py//tink/signature",
+ "@tink_py//tink/streaming_aead",
+ ],
+)
+
+py_test(
+ name = "supported_key_types_test",
+ srcs = ["supported_key_types_test.py"],
+ python_version = "PY3",
+ srcs_version = "PY3",
+ deps = [
+ ":supported_key_types",
+ requirement("absl-py"),
+ ],
+)
+
+py_library(
+ name = "_primitives",
+ srcs = ["_primitives.py"],
+ srcs_version = "PY3",
+ deps = [
+ ":testing_api_python_library",
+ "@com_google_protobuf//:protobuf_python",
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/signature",
+ "@tink_py//tink/streaming_aead",
+ requirement("absl-py"),
+ ],
+)
+
+py_library(
+ name = "testing_servers",
+ srcs = ["testing_servers.py"],
+ srcs_version = "PY3",
+ deps = [
+ ":_primitives",
+ ":testing_api_python_library",
+ "@com_google_protobuf//:protobuf_python",
+ "@tink_py//tink:cleartext_keyset_handle",
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/proto:tink_py_pb2",
+ "@tink_py//tink/signature",
+ "@tink_py//tink/streaming_aead",
+ requirement("absl-py"),
+ "@org_python_pypi_portpicker//:portpicker",
+ ],
+)
+
+py_test(
+ name = "testing_servers_test",
+ srcs = ["testing_servers_test.py"],
+ data = [
+ ":testing_servers",
+ ],
+ python_version = "PY3",
+ srcs_version = "PY3",
+ deps = [
+ ":testing_api_python_library",
+ requirement("absl-py"),
+ "@org_python_pypi_portpicker//:portpicker",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/signature",
+ "@tink_py//tink/streaming_aead",
+ ],
+)
+
+py_library(
+ name = "keyset_builder",
+ testonly = 1,
+ srcs = [
+ "keyset_builder.py",
+ ],
+ deps = [
+ "@tink_py//tink:cleartext_keyset_handle",
+ "@tink_py//tink:tink_python",
+ ],
+)
+
+py_test(
+ name = "keyset_builder_test",
+ srcs = ["keyset_builder_test.py"],
+ python_version = "PY3",
+ srcs_version = "PY3",
+ deps = [
+ ":keyset_builder",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ ],
+)
diff --git a/testing/cross_language/util/_primitives.py b/testing/cross_language/util/_primitives.py
new file mode 100644
index 0000000..933206d
--- /dev/null
+++ b/testing/cross_language/util/_primitives.py
@@ -0,0 +1,292 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Implements tink primitives from gRPC testing_api stubs."""
+
+from __future__ import absolute_import
+from __future__ import division
+# Placeholder for import for type annotations
+from __future__ import print_function
+
+import io
+from typing import BinaryIO, Text
+from absl import logging
+
+import tink
+from tink import aead
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature as tink_signature
+from tink import streaming_aead
+
+from tink.proto import tink_pb2
+from proto.testing import testing_api_pb2
+from proto.testing import testing_api_pb2_grpc
+
+
+def new_keyset(stub: testing_api_pb2_grpc.KeysetStub,
+ key_template: tink_pb2.KeyTemplate) -> bytes:
+ gen_request = testing_api_pb2.KeysetGenerateRequest(
+ template=key_template.SerializeToString())
+ gen_response = stub.Generate(gen_request)
+ if gen_response.err:
+ raise tink.TinkError(gen_response.err)
+ return gen_response.keyset
+
+
+def public_keyset(stub: testing_api_pb2_grpc.KeysetStub,
+ private_keyset: bytes) -> bytes:
+ request = testing_api_pb2.KeysetPublicRequest(private_keyset=private_keyset)
+ response = stub.Public(request)
+ if response.err:
+ raise tink.TinkError(response.err)
+ return response.public_keyset
+
+
+def keyset_to_json(
+ stub: testing_api_pb2_grpc.KeysetStub,
+ keyset: bytes) -> Text:
+ request = testing_api_pb2.KeysetToJsonRequest(keyset=keyset)
+ response = stub.ToJson(request)
+ if response.err:
+ raise tink.TinkError(response.err)
+ return response.json_keyset
+
+
+def keyset_from_json(
+ stub: testing_api_pb2_grpc.KeysetStub,
+ json_keyset: Text) -> bytes:
+ request = testing_api_pb2.KeysetFromJsonRequest(json_keyset=json_keyset)
+ response = stub.FromJson(request)
+ if response.err:
+ raise tink.TinkError(response.err)
+ return response.keyset
+
+
+class Aead(aead.Aead):
+ """Wraps AEAD service stub into an Aead primitive."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.AeadStub,
+ keyset: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._keyset = keyset
+
+ def encrypt(self, plaintext: bytes, associated_data: bytes) -> bytes:
+ logging.info('encrypt in lang %s.', self.lang)
+ enc_request = testing_api_pb2.AeadEncryptRequest(
+ keyset=self._keyset,
+ plaintext=plaintext,
+ associated_data=associated_data)
+ enc_response = self._stub.Encrypt(enc_request)
+ if enc_response.err:
+ logging.info('error encrypt in %s: %s', self.lang, enc_response.err)
+ raise tink.TinkError(enc_response.err)
+ return enc_response.ciphertext
+
+ def decrypt(self, ciphertext: bytes, associated_data: bytes) -> bytes:
+ logging.info('decrypt in lang %s.', self.lang)
+ dec_request = testing_api_pb2.AeadDecryptRequest(
+ keyset=self._keyset,
+ ciphertext=ciphertext,
+ associated_data=associated_data)
+ dec_response = self._stub.Decrypt(dec_request)
+ if dec_response.err:
+ logging.info('error decrypt in %s: %s', self.lang, dec_response.err)
+ raise tink.TinkError(dec_response.err)
+ return dec_response.plaintext
+
+
+class DeterministicAead(daead.DeterministicAead):
+ """Wraps DAEAD services stub into an DeterministicAead primitive."""
+
+ def __init__(self, lang: Text,
+ stub: testing_api_pb2_grpc.DeterministicAeadStub,
+ keyset: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._keyset = keyset
+
+ def encrypt_deterministically(self, plaintext: bytes,
+ associated_data: bytes) -> bytes:
+ """Encrypts."""
+ logging.info('encrypt in lang %s.', self.lang)
+ enc_request = testing_api_pb2.DeterministicAeadEncryptRequest(
+ keyset=self._keyset,
+ plaintext=plaintext,
+ associated_data=associated_data)
+ enc_response = self._stub.EncryptDeterministically(enc_request)
+ if enc_response.err:
+ logging.info('error encrypt in %s: %s', self.lang, enc_response.err)
+ raise tink.TinkError(enc_response.err)
+ return enc_response.ciphertext
+
+ def decrypt_deterministically(self, ciphertext: bytes,
+ associated_data: bytes) -> bytes:
+ """Decrypts."""
+ logging.info('decrypt in lang %s.', self.lang)
+ dec_request = testing_api_pb2.DeterministicAeadDecryptRequest(
+ keyset=self._keyset,
+ ciphertext=ciphertext,
+ associated_data=associated_data)
+ dec_response = self._stub.DecryptDeterministically(dec_request)
+ if dec_response.err:
+ logging.info('error decrypt in %s: %s', self.lang, dec_response.err)
+ raise tink.TinkError(dec_response.err)
+ return dec_response.plaintext
+
+
+class StreamingAead(streaming_aead.StreamingAead):
+ """Wraps Streaming AEAD service stub into a StreamingAead primitive."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.StreamingAeadStub,
+ keyset: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._keyset = keyset
+
+ def new_encrypting_stream(self, plaintext: BinaryIO,
+ associated_data: bytes) -> BinaryIO:
+ logging.info('encrypt in lang %s.', self.lang)
+ enc_request = testing_api_pb2.StreamingAeadEncryptRequest(
+ keyset=self._keyset,
+ plaintext=plaintext.read(),
+ associated_data=associated_data)
+ enc_response = self._stub.Encrypt(enc_request)
+ if enc_response.err:
+ logging.info('error encrypt in %s: %s', self.lang, enc_response.err)
+ raise tink.TinkError(enc_response.err)
+ return io.BytesIO(enc_response.ciphertext)
+
+ def new_decrypting_stream(self, ciphertext: BinaryIO,
+ associated_data: bytes) -> BinaryIO:
+ logging.info('decrypt in lang %s.', self.lang)
+ dec_request = testing_api_pb2.StreamingAeadDecryptRequest(
+ keyset=self._keyset,
+ ciphertext=ciphertext.read(),
+ associated_data=associated_data)
+ dec_response = self._stub.Decrypt(dec_request)
+ if dec_response.err:
+ logging.info('error decrypt in %s: %s', self.lang, dec_response.err)
+ raise tink.TinkError(dec_response.err)
+ return io.BytesIO(dec_response.plaintext)
+
+
+class Mac(mac.Mac):
+ """Wraps MAC service stub into an Mac primitive."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.MacStub,
+ keyset: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._keyset = keyset
+
+ def compute_mac(self, data: bytes) -> bytes:
+ logging.info('compute_mac in lang %s.', self.lang)
+ request = testing_api_pb2.ComputeMacRequest(keyset=self._keyset, data=data)
+ response = self._stub.ComputeMac(request)
+ if response.err:
+ logging.info('error compute_mac in %s: %s', self.lang, response.err)
+ raise tink.TinkError(response.err)
+ return response.mac_value
+
+ def verify_mac(self, mac_value: bytes, data: bytes) -> None:
+ logging.info('verify_mac in lang %s.', self.lang)
+ request = testing_api_pb2.VerifyMacRequest(
+ keyset=self._keyset, mac_value=mac_value, data=data)
+ response = self._stub.VerifyMac(request)
+ if response.err:
+ logging.info('error verify_mac in %s: %s', self.lang, response.err)
+ raise tink.TinkError(response.err)
+
+
+class HybridEncrypt(hybrid.HybridEncrypt):
+ """Implements the HybridEncrypt primitive using a hybrid service stub."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.HybridStub,
+ public_handle: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._public_handle = public_handle
+
+ def encrypt(self, plaintext: bytes, context_info: bytes) -> bytes:
+ logging.info('hybrid Sencrypt in lang %s.', self.lang)
+ enc_request = testing_api_pb2.HybridEncryptRequest(
+ public_keyset=self._public_handle,
+ plaintext=plaintext,
+ context_info=context_info)
+ enc_response = self._stub.Encrypt(enc_request)
+ if enc_response.err:
+ logging.info('error encrypt in %s: %s', self.lang, enc_response.err)
+ raise tink.TinkError(enc_response.err)
+ return enc_response.ciphertext
+
+
+class HybridDecrypt(hybrid.HybridDecrypt):
+ """Implements the HybridDecrypt primitive using a hybrid service stub."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.HybridStub,
+ private_handle: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._private_handle = private_handle
+
+ def decrypt(self, ciphertext: bytes, context_info: bytes) -> bytes:
+ logging.info('decrypt in lang %s.', self.lang)
+ dec_request = testing_api_pb2.HybridDecryptRequest(
+ private_keyset=self._private_handle,
+ ciphertext=ciphertext,
+ context_info=context_info)
+ dec_response = self._stub.Decrypt(dec_request)
+ if dec_response.err:
+ logging.info('error hybriddecrypt in %s: %s', self.lang, dec_response.err)
+ raise tink.TinkError(dec_response.err)
+ return dec_response.plaintext
+
+
+class PublicKeySign(tink_signature.PublicKeySign):
+ """Implements the PublicKeySign primitive using a signature service stub."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.SignatureStub,
+ private_handle: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._private_handle = private_handle
+
+ def sign(self, data: bytes) -> bytes:
+ logging.info('compute_mac in lang %s.', self.lang)
+ request = testing_api_pb2.SignatureSignRequest(
+ private_keyset=self._private_handle, data=data)
+ response = self._stub.Sign(request)
+ if response.err:
+ logging.info('error signature sign in %s: %s', self.lang, response.err)
+ raise tink.TinkError(response.err)
+ return response.signature
+
+
+class PublicKeyVerify(tink_signature.PublicKeyVerify):
+ """Implements the PublicKeyVerify primitive using a signature service stub."""
+
+ def __init__(self, lang: Text, stub: testing_api_pb2_grpc.SignatureStub,
+ public_handle: bytes) -> None:
+ self.lang = lang
+ self._stub = stub
+ self._public_handle = public_handle
+
+ def verify(self, signature: bytes, data: bytes) -> None:
+ logging.info('signature verify in lang %s.', self.lang)
+ request = testing_api_pb2.SignatureVerifyRequest(
+ public_keyset=self._public_handle, signature=signature, data=data)
+ response = self._stub.Verify(request)
+ if response.err:
+ logging.info('error signature verify in %s: %s', self.lang, response.err)
+ raise tink.TinkError(response.err)
diff --git a/testing/cross_language/util/keyset_builder.py b/testing/cross_language/util/keyset_builder.py
new file mode 100644
index 0000000..1993d20
--- /dev/null
+++ b/testing/cross_language/util/keyset_builder.py
@@ -0,0 +1,113 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Python implementation of a KeysetBuilder."""
+
+# Placeholder for import for type annotations
+
+import io
+import random
+import tink
+from tink import cleartext_keyset_handle
+from tink.proto import tink_pb2
+
+_MAX_INT32 = 4294967295 # 2^32-1
+
+
+def _new_key_data(key_template: tink_pb2.KeyTemplate) -> tink_pb2.KeyData:
+ return tink.core.Registry.new_key_data(key_template)
+
+
+def _generate_unused_key_id(keyset: tink_pb2.Keyset) -> int:
+ while True:
+ key_id = random.randint(1, _MAX_INT32)
+ if key_id not in {key.key_id for key in keyset.key}:
+ return key_id
+
+
+class KeysetBuilder(object):
+ """A KeysetBuilder provides convenience methods for managing Keysets.
+
+ It provides methods for adding, disabling, enabling, or deleting keys.
+ The validity of the keyset is checked when creating a keyset_handle.
+ """
+
+ def __init__(self, keyset_proto: tink_pb2.Keyset):
+ self._keyset = keyset_proto
+
+ def keyset_handle(self) -> tink.KeysetHandle:
+ keyset_copy = tink_pb2.Keyset()
+ keyset_copy.CopyFrom(self._keyset)
+ return cleartext_keyset_handle.from_keyset(keyset_copy)
+
+ def keyset(self) -> bytes:
+ return self._keyset.SerializeToString()
+
+ def add_new_key(self, key_template: tink_pb2.KeyTemplate) -> int:
+ """Generates a new key, adds it to the keyset, and returns its ID."""
+ new_key = self._keyset.key.add()
+ new_key.key_data.CopyFrom(_new_key_data(key_template))
+ new_key.status = tink_pb2.ENABLED
+ new_key_id = _generate_unused_key_id(self._keyset)
+ new_key.key_id = new_key_id
+ new_key.output_prefix_type = key_template.output_prefix_type
+ return new_key_id
+
+ def set_primary_key(self, key_id: int) -> None:
+ """Sets a key as primary."""
+ for key in self._keyset.key:
+ if key.key_id == key_id:
+ self._keyset.primary_key_id = key_id
+ return
+ raise tink.TinkError('key not found: %d' % key_id)
+
+ def enable_key(self, key_id: int) -> None:
+ """Enables a key."""
+ for key in self._keyset.key:
+ if key.key_id == key_id:
+ key.status = tink_pb2.ENABLED
+ return
+ raise tink.TinkError('key not found: %d' % key_id)
+
+ def disable_key(self, key_id: int) -> None:
+ """Disables a key."""
+ for key in self._keyset.key:
+ if key.key_id == key_id:
+ key.status = tink_pb2.DISABLED
+ return
+ raise tink.TinkError('key not found: %d' % key_id)
+
+ def delete_key(self, key_id: int) -> None:
+ """Deletes a key."""
+ for key in self._keyset.key:
+ if key.key_id == key_id:
+ self._keyset.key.remove(key)
+ return
+ raise tink.TinkError('key not found: %d' % key_id)
+
+
+def from_keyset(keyset: bytes) -> KeysetBuilder:
+ """Return a KeysetBuilder for a Keyset copied from a KeysetHandle."""
+ keyset_proto = tink_pb2.Keyset()
+ keyset_proto.ParseFromString(keyset)
+ return KeysetBuilder(keyset_proto)
+
+
+def from_keyset_handle(keyset_handle: tink.KeysetHandle) -> KeysetBuilder:
+ """Return a KeysetBuilder for a Keyset copied from a KeysetHandle."""
+ keyset_buffer = io.BytesIO()
+ cleartext_keyset_handle.write(
+ tink.BinaryKeysetWriter(keyset_buffer), keyset_handle)
+ return from_keyset(keyset_buffer.getvalue())
+
+
+def new_keyset_builder() -> KeysetBuilder:
+ return KeysetBuilder(tink_pb2.Keyset())
diff --git a/testing/cross_language/util/keyset_builder_test.py b/testing/cross_language/util/keyset_builder_test.py
new file mode 100644
index 0000000..26a0723
--- /dev/null
+++ b/testing/cross_language/util/keyset_builder_test.py
@@ -0,0 +1,132 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests for tink.testing.cross_language.util.keyset_builder."""
+
+from absl.testing import absltest
+# from absl.testing import parameterized
+
+import tink
+from tink import aead
+
+from util import keyset_builder
+
+
+def setUpModule():
+ aead.register()
+
+
+class KeysetBuilderTest(absltest.TestCase):
+
+ def test_keyset_handle_conversion(self):
+ keyset_handle1 = tink.new_keyset_handle(aead.aead_key_templates.AES128_GCM)
+ p1 = keyset_handle1.primitive(aead.Aead)
+ builder = keyset_builder.from_keyset_handle(keyset_handle1)
+ keyset_handle2 = builder.keyset_handle()
+ p2 = keyset_handle2.primitive(aead.Aead)
+ ciphertext = p1.encrypt(b'plaintext', b'ad')
+ self.assertEqual(p2.decrypt(ciphertext, b'ad'), b'plaintext')
+
+ def test_keyset_conversion(self):
+ builder1 = keyset_builder.new_keyset_builder()
+ new_key_id = builder1.add_new_key(aead.aead_key_templates.AES128_GCM)
+ builder1.set_primary_key(new_key_id)
+ keyset = builder1.keyset()
+ keyset_handle1 = builder1.keyset_handle()
+ p1 = keyset_handle1.primitive(aead.Aead)
+ builder2 = keyset_builder.from_keyset(keyset)
+ keyset_handle2 = builder2.keyset_handle()
+ p2 = keyset_handle2.primitive(aead.Aead)
+ ciphertext = p1.encrypt(b'plaintext', b'ad')
+ self.assertEqual(p2.decrypt(ciphertext, b'ad'), b'plaintext')
+
+ def test_add_new_key_new_id(self):
+ builder = keyset_builder.new_keyset_builder()
+ key_id1 = builder.add_new_key(aead.aead_key_templates.AES128_GCM)
+ key_id2 = builder.add_new_key(aead.aead_key_templates.AES128_GCM)
+ self.assertNotEqual(key_id1, key_id2)
+
+ def test_set_primary_success(self):
+ builder = keyset_builder.new_keyset_builder()
+ secondary_key_id = builder.add_new_key(aead.aead_key_templates.AES128_GCM)
+ builder.set_primary_key(secondary_key_id)
+
+ def test_operation_on_unknown_key_fails(self):
+ builder = keyset_builder.new_keyset_builder()
+ key_id = builder.add_new_key(
+ aead.aead_key_templates.AES128_GCM)
+ unknown_key_id = key_id + 1
+ with self.assertRaises(tink.TinkError):
+ builder.set_primary_key(unknown_key_id)
+ with self.assertRaises(tink.TinkError):
+ builder.enable_key(unknown_key_id)
+ with self.assertRaises(tink.TinkError):
+ builder.disable_key(unknown_key_id)
+ with self.assertRaises(tink.TinkError):
+ builder.delete_key(unknown_key_id)
+
+ def test_key_rotation(self):
+ builder = keyset_builder.new_keyset_builder()
+ older_key_id = builder.add_new_key(aead.aead_key_templates.AES128_GCM)
+ builder.set_primary_key(older_key_id)
+ p1 = builder.keyset_handle().primitive(aead.Aead)
+
+ newer_key_id = builder.add_new_key(aead.aead_key_templates.AES128_GCM)
+ p2 = builder.keyset_handle().primitive(aead.Aead)
+
+ builder.set_primary_key(newer_key_id)
+ p3 = builder.keyset_handle().primitive(aead.Aead)
+
+ builder.disable_key(older_key_id)
+ p4 = builder.keyset_handle().primitive(aead.Aead)
+
+ builder.delete_key(older_key_id)
+
+ self.assertNotEqual(older_key_id, newer_key_id)
+ # p1 encrypts with the older key. So p1, p2 and p3 can decrypt it,
+ # but not p4.
+ ciphertext1 = p1.encrypt(b'plaintext', b'ad')
+ self.assertEqual(p1.decrypt(ciphertext1, b'ad'), b'plaintext')
+ self.assertEqual(p2.decrypt(ciphertext1, b'ad'), b'plaintext')
+ self.assertEqual(p3.decrypt(ciphertext1, b'ad'), b'plaintext')
+ with self.assertRaises(tink.TinkError):
+ _ = p4.decrypt(ciphertext1, b'ad')
+
+ # p2 encrypts with the older key. So p1, p2 and p3 can decrypt it,
+ # but not p4.
+ ciphertext2 = p2.encrypt(b'plaintext', b'ad')
+ self.assertEqual(p1.decrypt(ciphertext2, b'ad'), b'plaintext')
+ self.assertEqual(p2.decrypt(ciphertext2, b'ad'), b'plaintext')
+ self.assertEqual(p3.decrypt(ciphertext2, b'ad'), b'plaintext')
+ with self.assertRaises(tink.TinkError):
+ _ = p4.decrypt(ciphertext2, b'ad')
+
+ # p3 encrypts with the newer key. So p2, p3 and p4 can decrypt it,
+ # but not p1.
+ ciphertext3 = p3.encrypt(b'plaintext', b'ad')
+ with self.assertRaises(tink.TinkError):
+ _ = p1.decrypt(ciphertext3, b'ad')
+ self.assertEqual(p2.decrypt(ciphertext3, b'ad'), b'plaintext')
+ self.assertEqual(p3.decrypt(ciphertext3, b'ad'), b'plaintext')
+ self.assertEqual(p4.decrypt(ciphertext3, b'ad'), b'plaintext')
+
+ # p4 encrypts with the newer key. So p2, p3 and p4 can decrypt it,
+ # but not p1.
+ ciphertext4 = p3.encrypt(b'plaintext', b'ad')
+ with self.assertRaises(tink.TinkError):
+ _ = p1.decrypt(ciphertext4, b'ad')
+ self.assertEqual(p2.decrypt(ciphertext4, b'ad'), b'plaintext')
+ self.assertEqual(p3.decrypt(ciphertext4, b'ad'), b'plaintext')
+ self.assertEqual(p4.decrypt(ciphertext4, b'ad'), b'plaintext')
+
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/tools/testing/supported_key_types.py b/testing/cross_language/util/supported_key_types.py
similarity index 81%
rename from tools/testing/supported_key_types.py
rename to testing/cross_language/util/supported_key_types.py
index 6ea2f32..91c7fa5 100644
--- a/tools/testing/supported_key_types.py
+++ b/testing/cross_language/util/supported_key_types.py
@@ -13,13 +13,14 @@
# Placeholder for import for type annotations
+from typing import Iterable, List, Text, Tuple
+
from tink import aead
from tink import daead
from tink import hybrid
from tink import mac
from tink import signature
-
-from typing import Iterable, List, Text, Tuple
+from tink import streaming_aead
from tink.proto import tink_pb2
@@ -32,20 +33,24 @@
'AesGcmKey',
'AesCtrHmacAeadKey',
'ChaCha20Poly1305Key',
- 'XChaCha20Poly1305Key'
+ 'XChaCha20Poly1305Key',
]
DAEAD_KEY_TYPES = ['AesSivKey']
+STREAMING_AEAD_KEY_TYPES = [
+ 'AesCtrHmacStreamingKey',
+ 'AesGcmHkdfStreamingKey',
+]
HYBRID_PRIVATE_KEY_TYPES = ['EciesAeadHkdfPrivateKey']
MAC_KEY_TYPES = ['HmacKey']
SIGNATURE_KEY_TYPES = [
'EcdsaPrivateKey',
'Ed25519PrivateKey',
'RsaSsaPkcs1PrivateKey',
- 'RsaSsaPssPrivateKey'
+ 'RsaSsaPssPrivateKey',
]
ALL_KEY_TYPES = (
- AEAD_KEY_TYPES + DAEAD_KEY_TYPES + HYBRID_PRIVATE_KEY_TYPES +
- MAC_KEY_TYPES + SIGNATURE_KEY_TYPES)
+ AEAD_KEY_TYPES + DAEAD_KEY_TYPES + STREAMING_AEAD_KEY_TYPES +
+ HYBRID_PRIVATE_KEY_TYPES + MAC_KEY_TYPES + SIGNATURE_KEY_TYPES)
# All languages that are supported by a KeyType
SUPPORTED_LANGUAGES = {
@@ -55,6 +60,8 @@
'ChaCha20Poly1305Key': ['java', 'go'],
'XChaCha20Poly1305Key': ['cc', 'java', 'go', 'python'],
'AesSivKey': ['cc', 'java', 'go', 'python'],
+ 'AesCtrHmacStreamingKey': ['cc', 'java'],
+ 'AesGcmHkdfStreamingKey': ['cc', 'java', 'go'],
'EciesAeadHkdfPrivateKey': ['cc', 'java', 'go', 'python'],
'HmacKey': ['cc', 'java', 'go', 'python'],
'EcdsaPrivateKey': ['cc', 'java', 'go', 'python'],
@@ -63,6 +70,10 @@
'RsaSsaPssPrivateKey': ['cc', 'java', 'python'],
}
+SUPPORTED_LANGUAGES_PER_TYPE_URL = {
+ 'type.googleapis.com/google.crypto.tink.' + name: langs
+ for name, langs in SUPPORTED_LANGUAGES.items()}
+
# For each KeyType, a list of all KeyTemplate Names that must be supported.
KEY_TEMPLATE_NAMES = {
'AesEaxKey': ['AES128_EAX', 'AES256_EAX'],
@@ -71,6 +82,15 @@
'ChaCha20Poly1305Key': ['CHACHA20_POLY1305'],
'XChaCha20Poly1305Key': ['XCHACHA20_POLY1305'],
'AesSivKey': ['AES256_SIV'],
+ 'AesCtrHmacStreamingKey': [
+ 'AES128_CTR_HMAC_SHA256_4KB',
+ 'AES256_CTR_HMAC_SHA256_4KB',
+ ],
+ 'AesGcmHkdfStreamingKey': [
+ 'AES128_GCM_HKDF_4KB',
+ 'AES256_GCM_HKDF_4KB',
+ 'AES256_GCM_HKDF_1MB',
+ ],
'EciesAeadHkdfPrivateKey': [
'ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM',
'ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256'
@@ -123,6 +143,16 @@
aead.aead_key_templates.XCHACHA20_POLY1305,
'AES256_SIV':
daead.deterministic_aead_key_templates.AES256_SIV,
+ 'AES128_CTR_HMAC_SHA256_4KB':
+ streaming_aead.streaming_aead_key_templates.AES128_CTR_HMAC_SHA256_4KB,
+ 'AES256_CTR_HMAC_SHA256_4KB':
+ streaming_aead.streaming_aead_key_templates.AES256_CTR_HMAC_SHA256_4KB,
+ 'AES128_GCM_HKDF_4KB':
+ streaming_aead.streaming_aead_key_templates.AES128_GCM_HKDF_4KB,
+ 'AES256_GCM_HKDF_4KB':
+ streaming_aead.streaming_aead_key_templates.AES256_GCM_HKDF_4KB,
+ 'AES256_GCM_HKDF_1MB':
+ streaming_aead.streaming_aead_key_templates.AES256_GCM_HKDF_1MB,
'ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM':
hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM,
'ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256':
diff --git a/tools/testing/supported_key_types_test.py b/testing/cross_language/util/supported_key_types_test.py
similarity index 92%
rename from tools/testing/supported_key_types_test.py
rename to testing/cross_language/util/supported_key_types_test.py
index a113024..9ea4c39 100644
--- a/tools/testing/supported_key_types_test.py
+++ b/testing/cross_language/util/supported_key_types_test.py
@@ -9,10 +9,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Tests for tink.tools.testing.supported_key_types."""
+"""Tests for tink.testing.cross_language.supported_key_types."""
from absl.testing import absltest
-from google3.third_party.tink.tools.testing import supported_key_types
+from util import supported_key_types
class SupportedKeyTypesTest(absltest.TestCase):
diff --git a/testing/cross_language/util/testing_servers.py b/testing/cross_language/util/testing_servers.py
new file mode 100644
index 0000000..f1e908f
--- /dev/null
+++ b/testing/cross_language/util/testing_servers.py
@@ -0,0 +1,283 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""testing_server starts up testing gRPC servers in different languages."""
+
+from __future__ import absolute_import
+from __future__ import division
+# Placeholder for import for type annotations
+from __future__ import print_function
+
+import os
+import subprocess
+import time
+
+from typing import List, Text
+from absl import logging
+import grpc
+import portpicker
+
+from tink.proto import tink_pb2
+from proto.testing import testing_api_pb2
+from proto.testing import testing_api_pb2_grpc
+from util import _primitives
+
+# Server paths are relative to os.environ['testing_dir'], which can be set by:
+# bazel test util:testing_servers_test --test_env testing_dir=/tmp/tink/testing
+# If not set, the testing_dir is calcuated from os.path.abspath(__file__).
+_SERVER_PATHS = {
+ 'cc': [
+ 'cc/bazel-bin/testing_server',
+ 'cc/testing_server'
+ ],
+ 'go': [
+ 'go/bazel-bin/linux_amd64_stripped/testing_server',
+ 'go/testing_server'
+ ],
+ 'java': [
+ 'java_src/bazel-bin/testing_server_deploy.jar',
+ 'java_src/testing_server'
+ ],
+ 'python': [
+ 'python/bazel-bin/testing_server',
+ 'python/testing_server',
+ ]
+}
+
+# All languages that have a testing server
+LANGUAGES = list(_SERVER_PATHS.keys())
+
+# location of the testing_server java binary, relative to testing_dir
+_JAVA_PATH = 'java_src/bazel-bin/testing_server.runfiles/local_jdk/bin/java'
+
+_PRIMITIVE_STUBS = {
+ 'aead': testing_api_pb2_grpc.AeadStub,
+ 'daead': testing_api_pb2_grpc.DeterministicAeadStub,
+ 'streaming_aead': testing_api_pb2_grpc.StreamingAeadStub,
+ 'hybrid': testing_api_pb2_grpc.HybridStub,
+ 'mac': testing_api_pb2_grpc.MacStub,
+ 'signature': testing_api_pb2_grpc.SignatureStub,
+}
+
+# All primitives.
+_PRIMITIVES = list(_PRIMITIVE_STUBS.keys())
+
+SUPPORTED_LANGUAGES_BY_PRIMITIVE = {
+ 'aead': ['cc', 'go', 'java', 'python'],
+ 'daead': ['cc', 'go', 'java', 'python'],
+ 'streaming_aead': ['cc', 'go', 'java'],
+ 'hybrid': ['cc', 'go', 'java', 'python'],
+ 'mac': ['cc', 'go', 'java', 'python'],
+ 'signature': ['cc', 'go', 'java', 'python'],
+}
+
+
+def _server_path(lang: Text) -> Text:
+ """Returns the path where the server binary is located."""
+ if os.environ.get('testing_dir'):
+ testing_dir = os.environ.get('testing_dir')
+ else:
+ util_dir = os.path.dirname(os.path.abspath(__file__))
+ testing_dir = os.path.dirname(os.path.dirname(util_dir))
+ for relative_server_path in _SERVER_PATHS[lang]:
+ server_path = os.path.join(testing_dir, relative_server_path)
+ logging.info('try path: %s', server_path)
+ if os.path.exists(server_path):
+ return server_path
+ raise RuntimeError('Executable for lang %s not found' % lang)
+
+
+def _server_cmd(lang: Text, port: int) -> List[Text]:
+ server_path = _server_path(lang)
+ if lang == 'java' and server_path.endswith('.jar'):
+ java_path = os.path.join(os.environ.get('testing_dir'), _JAVA_PATH)
+ return [java_path, '-jar', server_path, '--port', '%d' % port]
+ else:
+ return [server_path, '--port', '%d' % port]
+
+
+class _TestingServers():
+ """TestingServers starts up testing gRPC servers and returns service stubs."""
+
+ def __init__(self):
+ self._server = {}
+ self._channel = {}
+ self._metadata_stub = {}
+ self._keyset_stub = {}
+ self._aead_stub = {}
+ self._daead_stub = {}
+ self._streaming_aead_stub = {}
+ self._hybrid_stub = {}
+ self._mac_stub = {}
+ self._signature_stub = {}
+ for lang in LANGUAGES:
+ port = portpicker.pick_unused_port()
+ cmd = _server_cmd(lang, port)
+ logging.info('cmd = %s', cmd)
+ self._server[lang] = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ logging.info('%s server started on port %d with pid: %d.',
+ lang, port, self._server[lang].pid)
+ self._channel[lang] = grpc.secure_channel(
+ '[::]:%d' % port, grpc.local_channel_credentials())
+ for lang in LANGUAGES:
+ try:
+ grpc.channel_ready_future(self._channel[lang]).result(timeout=30)
+ except:
+ logging.info('Timeout while connecting to server %s', lang)
+ self._server[lang].kill()
+ out, err = self._server[lang].communicate()
+ raise RuntimeError(
+ 'Could not start %s server, output=%s, err=%s' % (lang, out, err))
+ self._metadata_stub[lang] = testing_api_pb2_grpc.MetadataStub(
+ self._channel[lang])
+ self._keyset_stub[lang] = testing_api_pb2_grpc.KeysetStub(
+ self._channel[lang])
+ for primitive in _PRIMITIVES:
+ for lang in SUPPORTED_LANGUAGES_BY_PRIMITIVE[primitive]:
+ stub_name = '_%s_stub' % primitive
+ getattr(self, stub_name)[lang] = _PRIMITIVE_STUBS[primitive](
+ self._channel[lang])
+
+ def keyset_stub(self, lang) -> testing_api_pb2_grpc.KeysetStub:
+ return self._keyset_stub[lang]
+
+ def aead_stub(self, lang) -> testing_api_pb2_grpc.AeadStub:
+ return self._aead_stub[lang]
+
+ def daead_stub(self, lang) -> testing_api_pb2_grpc.DeterministicAeadStub:
+ return self._daead_stub[lang]
+
+ def streaming_aead_stub(self, lang) -> testing_api_pb2_grpc.StreamingAeadStub:
+ return self._streaming_aead_stub[lang]
+
+ def hybrid_stub(self, lang) -> testing_api_pb2_grpc.HybridStub:
+ return self._hybrid_stub[lang]
+
+ def mac_stub(self, lang) -> testing_api_pb2_grpc.MacStub:
+ return self._mac_stub[lang]
+
+ def signature_stub(self, lang) -> testing_api_pb2_grpc.SignatureStub:
+ return self._signature_stub[lang]
+
+ def metadata_stub(self, lang) -> testing_api_pb2_grpc.MetadataStub:
+ return self._metadata_stub[lang]
+
+ def stop(self):
+ """Stops all servers."""
+ logging.info('Stopping servers...')
+ for lang in LANGUAGES:
+ self._channel[lang].close()
+ for lang in LANGUAGES:
+ self._server[lang].terminate()
+ time.sleep(2)
+ for lang in LANGUAGES:
+ if self._server[lang].poll() is None:
+ logging.info('Killing server %s.', lang)
+ self._server[lang].kill()
+ logging.info('All servers stopped.')
+
+
+_ts = None
+
+
+def start() -> None:
+ """Starts all servers."""
+ global _ts
+ _ts = _TestingServers()
+
+ for lang in LANGUAGES:
+ response = _ts.metadata_stub(lang).GetServerInfo(
+ testing_api_pb2.ServerInfoRequest())
+ if lang != response.language:
+ raise ValueError(
+ 'lang = %s != response.language = %s' % (lang, response.language))
+ logging.info('server_info:\n%s', response)
+
+
+def stop() -> None:
+ """Stops all servers."""
+ global _ts
+ _ts.stop()
+
+
+def new_keyset(lang: Text, key_template: tink_pb2.KeyTemplate) -> bytes:
+ """Returns a new KeysetHandle, implemented in lang."""
+ global _ts
+ return _primitives.new_keyset(_ts.keyset_stub(lang), key_template)
+
+
+def public_keyset(lang: Text, private_keyset: bytes) -> bytes:
+ """Returns a public keyset handle, implemented in lang."""
+ global _ts
+ return _primitives.public_keyset(_ts.keyset_stub(lang), private_keyset)
+
+
+def keyset_to_json(lang: Text, keyset: bytes) -> Text:
+ global _ts
+ return _primitives.keyset_to_json(_ts.keyset_stub(lang), keyset)
+
+
+def keyset_from_json(lang: Text, json_keyset: Text) -> bytes:
+ global _ts
+ return _primitives.keyset_from_json(_ts.keyset_stub(lang), json_keyset)
+
+
+def aead(lang: Text, keyset: bytes) -> _primitives.Aead:
+ """Returns an AEAD primitive, implemented in lang."""
+ global _ts
+ return _primitives.Aead(lang, _ts.aead_stub(lang), keyset)
+
+
+def deterministic_aead(lang: Text,
+ keyset: bytes) -> _primitives.DeterministicAead:
+ """Returns a DeterministicAEAD primitive, implemented in lang."""
+ global _ts
+ return _primitives.DeterministicAead(lang, _ts.daead_stub(lang), keyset)
+
+
+def streaming_aead(lang: Text, key_handle: bytes) -> _primitives.StreamingAead:
+ """Returns a StreamingAEAD primitive, implemented in lang."""
+ global _ts
+ return _primitives.StreamingAead(
+ lang, _ts.streaming_aead_stub(lang), key_handle)
+
+
+def hybrid_encrypt(lang: Text, pub_keyset: bytes) -> _primitives.HybridEncrypt:
+ """Returns a HybridEncrypt primitive, implemented in lang."""
+ global _ts
+ return _primitives.HybridEncrypt(lang, _ts.hybrid_stub(lang), pub_keyset)
+
+
+def hybrid_decrypt(lang: Text, priv_keyset: bytes) -> _primitives.HybridDecrypt:
+ """Returns a HybridDecrypt primitive, implemented in lang."""
+ global _ts
+ return _primitives.HybridDecrypt(lang, _ts.hybrid_stub(lang), priv_keyset)
+
+
+def mac(lang: Text, keyset: bytes) -> _primitives.Mac:
+ """Returns a MAC primitive, implemented in lang."""
+ global _ts
+ return _primitives.Mac(lang, _ts.mac_stub(lang), keyset)
+
+
+def public_key_sign(lang: Text,
+ priv_keyset: bytes) -> _primitives.PublicKeySign:
+ """Returns an PublicKeySign primitive, implemented in lang."""
+ global _ts
+ return _primitives.PublicKeySign(lang, _ts.signature_stub(lang), priv_keyset)
+
+
+def public_key_verify(lang: Text,
+ pub_keyset: bytes) -> _primitives.PublicKeyVerify:
+ """Returns an PublicKeyVerify primitive, implemented in lang."""
+ global _ts
+ return _primitives.PublicKeyVerify(lang, _ts.signature_stub(lang), pub_keyset)
diff --git a/testing/cross_language/util/testing_servers_test.py b/testing/cross_language/util/testing_servers_test.py
new file mode 100644
index 0000000..c19cf72
--- /dev/null
+++ b/testing/cross_language/util/testing_servers_test.py
@@ -0,0 +1,160 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests for tink.testing.cross_language.util.testing_server."""
+
+import io
+
+from absl.testing import absltest
+from absl.testing import parameterized
+
+import tink
+from tink import aead
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature
+from tink import streaming_aead
+
+from util import testing_servers
+
+_SUPPORTED_LANGUAGES = testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE
+
+
+class TestingServersConfigTest(absltest.TestCase):
+
+ def test_primitives(self):
+ self.assertEqual(
+ testing_servers._PRIMITIVE_STUBS.keys(),
+ _SUPPORTED_LANGUAGES.keys(),
+ msg=(
+ 'The primitives specified as keys in '
+ 'testing_servers._PRIMITIVE_STUBS must match the primitives '
+ ' specified as keys in '
+ 'testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE.'
+ ))
+
+ def test_languages(self):
+ for primitive in _SUPPORTED_LANGUAGES:
+ languages = set(testing_servers.LANGUAGES)
+ supported_languages = set(_SUPPORTED_LANGUAGES[primitive])
+ self.assertContainsSubset(supported_languages, languages, msg=(
+ 'The languages specified in '
+ 'testing_servers.SUPPORTED_LANGUAGES_BY_PRIMITIVE must be a subset '
+ 'of the languages specified in testing_servers.LANGUAGES.'
+ ))
+
+
+class TestingServersTest(parameterized.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestingServersTest, cls).setUpClass()
+ testing_servers.start()
+
+ @classmethod
+ def tearDownClass(cls):
+ testing_servers.stop()
+ super(TestingServersTest, cls).tearDownClass()
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['aead'])
+ def test_aead(self, lang):
+ keyset = testing_servers.new_keyset(lang,
+ aead.aead_key_templates.AES128_GCM)
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ associated_data = b'associated_data'
+ aead_primitive = testing_servers.aead(lang, keyset)
+ ciphertext = aead_primitive.encrypt(plaintext, associated_data)
+ output = aead_primitive.decrypt(ciphertext, associated_data)
+ self.assertEqual(output, plaintext)
+
+ with self.assertRaises(tink.TinkError):
+ aead_primitive.decrypt(b'foo', associated_data)
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['daead'])
+ def test_daead(self, lang):
+ keyset = testing_servers.new_keyset(
+ lang, daead.deterministic_aead_key_templates.AES256_SIV)
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ associated_data = b'associated_data'
+ daead_primitive = testing_servers.deterministic_aead(lang, keyset)
+ ciphertext = daead_primitive.encrypt_deterministically(
+ plaintext, associated_data)
+ output = daead_primitive.decrypt_deterministically(
+ ciphertext, associated_data)
+ self.assertEqual(output, plaintext)
+
+ with self.assertRaises(tink.TinkError):
+ daead_primitive.decrypt_deterministically(b'foo', associated_data)
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['streaming_aead'])
+ def test_streaming_aead(self, lang):
+ keyset = testing_servers.new_keyset(
+ lang, streaming_aead.streaming_aead_key_templates.AES128_GCM_HKDF_4KB)
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ plaintext_stream = io.BytesIO(plaintext)
+ associated_data = b'associated_data'
+ streaming_aead_primitive = testing_servers.streaming_aead(lang, keyset)
+ ciphertext_stream = streaming_aead_primitive.new_encrypting_stream(
+ plaintext_stream, associated_data)
+ output_stream = streaming_aead_primitive.new_decrypting_stream(
+ ciphertext_stream, associated_data)
+ self.assertEqual(output_stream.read(), plaintext)
+
+ with self.assertRaises(tink.TinkError):
+ streaming_aead_primitive.new_decrypting_stream(io.BytesIO(b'foo'),
+ associated_data)
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['mac'])
+ def test_mac(self, lang):
+ keyset = testing_servers.new_keyset(
+ lang, mac.mac_key_templates.HMAC_SHA256_128BITTAG)
+ data = b'The quick brown fox jumps over the lazy dog'
+ mac_primitive = testing_servers.mac(lang, keyset)
+ mac_value = mac_primitive.compute_mac(data)
+ mac_primitive.verify_mac(mac_value, data)
+
+ with self.assertRaises(tink.TinkError):
+ mac_primitive.verify_mac(b'foo', data)
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['hybrid'])
+ def test_hybrid(self, lang):
+ private_handle = testing_servers.new_keyset(
+ lang,
+ hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)
+ public_handle = testing_servers.public_keyset(lang, private_handle)
+ enc_primitive = testing_servers.hybrid_encrypt(lang, public_handle)
+ data = b'The quick brown fox jumps over the lazy dog'
+ context_info = b'context'
+ ciphertext = enc_primitive.encrypt(data, context_info)
+ dec_primitive = testing_servers.hybrid_decrypt(lang, private_handle)
+ output = dec_primitive.decrypt(ciphertext, context_info)
+ self.assertEqual(output, data)
+
+ with self.assertRaises(tink.TinkError):
+ dec_primitive.decrypt(b'foo', context_info)
+
+ @parameterized.parameters(_SUPPORTED_LANGUAGES['signature'])
+ def test_signature(self, lang):
+ private_handle = testing_servers.new_keyset(
+ lang, signature.signature_key_templates.ED25519)
+ public_handle = testing_servers.public_keyset(lang, private_handle)
+ sign_primitive = testing_servers.public_key_sign(lang, private_handle)
+ data = b'The quick brown fox jumps over the lazy dog'
+ signature_value = sign_primitive.sign(data)
+ verify_primitive = testing_servers.public_key_verify(lang, public_handle)
+ verify_primitive.verify(signature_value, data)
+
+ with self.assertRaises(tink.TinkError):
+ verify_primitive.verify(b'foo', data)
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/testing/go/.bazelversion b/testing/go/.bazelversion
new file mode 100644
index 0000000..fd2a018
--- /dev/null
+++ b/testing/go/.bazelversion
@@ -0,0 +1 @@
+3.1.0
diff --git a/testing/go/BUILD.bazel b/testing/go/BUILD.bazel
new file mode 100644
index 0000000..f4595da
--- /dev/null
+++ b/testing/go/BUILD.bazel
@@ -0,0 +1,73 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+load("@rules_proto_grpc//go:defs.bzl", "go_grpc_library")
+
+package(
+ default_testonly = 1,
+ default_visibility = ["//:__subpackages__"],
+)
+
+licenses(["notice"])
+
+go_grpc_library(
+ name = "testing_api_go_grpc",
+ importpath = "github.com/google/tink/proto/testing/testing_api_go_grpc",
+ deps = ["@tink_base//proto/testing:testing_api_proto"],
+)
+
+go_library(
+ name = "services",
+ srcs = [
+ "aead_service.go",
+ "daead_service.go",
+ "hybrid_service.go",
+ "keyset_service.go",
+ "mac_service.go",
+ "metadata_service.go",
+ "signature_service.go",
+ "streaming_aead_service.go",
+ ],
+ importpath = "github.com/google/tink/testing/go/services",
+ deps = [
+ ":testing_api_go_grpc",
+ "@com_github_golang_protobuf//proto:go_default_library",
+ "@tink_go//aead:go_default_library",
+ "@tink_go//daead:go_default_library",
+ "@tink_go//hybrid:go_default_library",
+ "@tink_go//keyset:go_default_library",
+ "@tink_go//mac:go_default_library",
+ "@tink_go//proto:tink_go_proto",
+ "@tink_go//signature:go_default_library",
+ "@tink_go//streamingaead:go_default_library",
+ "@tink_go//testkeyset:go_default_library",
+ ],
+)
+
+go_test(
+ name = "services_test",
+ size = "small",
+ srcs = ["services_test.go"],
+ deps = [
+ ":services",
+ ":testing_api_go_grpc",
+ "@com_github_golang_protobuf//proto:go_default_library",
+ "@tink_go//aead:go_default_library",
+ "@tink_go//daead:go_default_library",
+ "@tink_go//hybrid:go_default_library",
+ "@tink_go//keyset:go_default_library",
+ "@tink_go//mac:go_default_library",
+ "@tink_go//signature:go_default_library",
+ "@tink_go//streamingaead:go_default_library",
+ ],
+)
+
+go_binary(
+ name = "testing_server",
+ srcs = [
+ "testing_server.go",
+ ],
+ deps = [
+ ":services",
+ ":testing_api_go_grpc",
+ "@org_golang_google_grpc//:go_default_library",
+ ],
+)
diff --git a/testing/go/WORKSPACE b/testing/go/WORKSPACE
new file mode 100644
index 0000000..c9ef526
--- /dev/null
+++ b/testing/go/WORKSPACE
@@ -0,0 +1,302 @@
+workspace(name = "testing_go")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "tink_base",
+ path = "../..",
+)
+
+local_repository(
+ name = "tink_go",
+ path = "../../go",
+)
+
+load("@tink_base//:tink_base_deps.bzl", "tink_base_deps")
+tink_base_deps()
+
+load("@tink_base//:tink_base_deps_init.bzl", "tink_base_deps_init")
+tink_base_deps_init()
+
+load("@tink_go//:tink_go_deps.bzl", "tink_go_deps")
+tink_go_deps()
+
+http_archive(
+ name = "rules_proto",
+ sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208",
+ strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
+ "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
+ ],
+)
+load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
+rules_proto_dependencies()
+rules_proto_toolchains()
+
+http_archive(
+ name = "rules_proto_grpc",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+)
+
+load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos", "bazel_gazelle", "io_bazel_rules_go")
+
+rules_proto_grpc_toolchains()
+rules_proto_grpc_repos()
+
+io_bazel_rules_go()
+
+# Go initialization does not work via tink_go_deps_init for some reason.
+# All of the Go-init stuff is for now just copied from Go-WORKSPACE.
+load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+
+go_rules_dependencies()
+go_register_toolchains(nogo = "@//go:tink_nogo")
+
+bazel_gazelle()
+
+load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
+
+gazelle_dependencies()
+
+load("@rules_proto_grpc//go:repositories.bzl", rules_proto_grpc_go_repos="go_repos")
+
+rules_proto_grpc_go_repos()
+
+# How to update go dependencies:
+# 1) Remove all go_repository rules in WORKSPACE.bazel
+# 2) Update the files go.mod and go.sum. This can be done as follows:
+# 2.1) Replacing all versions in go.mod with "latest".
+# 2.2) Run "go mod tidy".
+# 3) Update the WORKSPACE.bazel file by running
+# bazel run //:gazelle -- update-repos -from_file=go.mod
+# Put the go repository rules in the right place.
+go_repository(
+ name = "co_honnef_go_tools",
+ importpath = "honnef.co/go/tools",
+ sum = "h1:LJwr7TCTghdatWv40WobzlKXc9c4s8oGa7QKJUtHhWA=",
+ version = "v0.0.0-20190418001031-e561f6794a2a",
+)
+go_repository(
+ name = "com_github_aws_aws_sdk_go",
+ importpath = "github.com/aws/aws-sdk-go",
+ sum = "h1:1xxya3nsUaFlEZuoE5PWsIEd47RoDV/kkOGt0qEuwNw=",
+ version = "v1.25.39",
+)
+go_repository(
+ name = "com_github_burntsushi_toml",
+ importpath = "github.com/BurntSushi/toml",
+ sum = "h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=",
+ version = "v0.3.1",
+)
+go_repository(
+ name = "com_github_client9_misspell",
+ importpath = "github.com/client9/misspell",
+ sum = "h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=",
+ version = "v0.3.4",
+)
+go_repository(
+ name = "com_github_davecgh_go_spew",
+ importpath = "github.com/davecgh/go-spew",
+ sum = "h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=",
+ version = "v1.1.0",
+)
+go_repository(
+ name = "com_github_golang_glog",
+ importpath = "github.com/golang/glog",
+ sum = "h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=",
+ version = "v0.0.0-20160126235308-23def4e6c14b",
+)
+go_repository(
+ name = "com_github_golang_mock",
+ importpath = "github.com/golang/mock",
+ sum = "h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=",
+ version = "v1.2.0",
+)
+go_repository(
+ name = "com_github_golang_protobuf",
+ importpath = "github.com/golang/protobuf",
+ sum = "h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=",
+ version = "v1.3.2",
+)
+go_repository(
+ name = "com_github_google_btree",
+ importpath = "github.com/google/btree",
+ sum = "h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=",
+ version = "v0.0.0-20180813153112-4030bb1f1f0c",
+)
+go_repository(
+ name = "com_github_google_go_cmp",
+ importpath = "github.com/google/go-cmp",
+ sum = "h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=",
+ version = "v0.3.0",
+)
+go_repository(
+ name = "com_github_google_martian",
+ importpath = "github.com/google/martian",
+ sum = "h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=",
+ version = "v2.1.0+incompatible",
+)
+go_repository(
+ name = "com_github_google_pprof",
+ importpath = "github.com/google/pprof",
+ sum = "h1:eqyIo2HjKhKe/mJzTG8n4VqvLXIOEG+SLdDqX7xGtkY=",
+ version = "v0.0.0-20181206194817-3ea8567a2e57",
+)
+go_repository(
+ name = "com_github_googleapis_gax_go_v2",
+ importpath = "github.com/googleapis/gax-go/v2",
+ sum = "h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=",
+ version = "v2.0.5",
+)
+go_repository(
+ name = "com_github_hashicorp_golang_lru",
+ importpath = "github.com/hashicorp/golang-lru",
+ sum = "h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=",
+ version = "v0.5.1",
+)
+go_repository(
+ name = "com_github_jmespath_go_jmespath",
+ importpath = "github.com/jmespath/go-jmespath",
+ sum = "h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=",
+ version = "v0.0.0-20180206201540-c2b33e8439af",
+)
+go_repository(
+ name = "com_github_jstemmer_go_junit_report",
+ importpath = "github.com/jstemmer/go-junit-report",
+ sum = "h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=",
+ version = "v0.0.0-20190106144839-af01ea7f8024",
+)
+go_repository(
+ name = "com_github_pmezard_go_difflib",
+ importpath = "github.com/pmezard/go-difflib",
+ sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=",
+ version = "v1.0.0",
+)
+go_repository(
+ name = "com_github_stretchr_objx",
+ importpath = "github.com/stretchr/objx",
+ sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=",
+ version = "v0.1.0",
+)
+go_repository(
+ name = "com_github_stretchr_testify",
+ importpath = "github.com/stretchr/testify",
+ sum = "h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=",
+ version = "v1.4.0",
+)
+go_repository(
+ name = "com_google_cloud_go",
+ importpath = "cloud.google.com/go",
+ sum = "h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=",
+ version = "v0.38.0",
+)
+go_repository(
+ name = "in_gopkg_check_v1",
+ importpath = "gopkg.in/check.v1",
+ sum = "h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=",
+ version = "v0.0.0-20161208181325-20d25e280405",
+)
+go_repository(
+ name = "in_gopkg_yaml_v2",
+ importpath = "gopkg.in/yaml.v2",
+ sum = "h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=",
+ version = "v2.2.2",
+)
+go_repository(
+ name = "io_opencensus_go",
+ importpath = "go.opencensus.io",
+ sum = "h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=",
+ version = "v0.21.0",
+)
+go_repository(
+ name = "org_golang_google_api",
+ importpath = "google.golang.org/api",
+ sum = "h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE=",
+ version = "v0.14.0",
+)
+go_repository(
+ name = "org_golang_google_appengine",
+ importpath = "google.golang.org/appengine",
+ sum = "h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=",
+ version = "v1.5.0",
+)
+go_repository(
+ name = "org_golang_google_genproto",
+ importpath = "google.golang.org/genproto",
+ sum = "h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=",
+ version = "v0.0.0-20190502173448-54afdca5d873",
+)
+go_repository(
+ name = "org_golang_google_grpc",
+ importpath = "google.golang.org/grpc",
+ sum = "h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=",
+ version = "v1.20.1",
+)
+go_repository(
+ name = "org_golang_x_crypto",
+ importpath = "golang.org/x/crypto",
+ sum = "h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE=",
+ version = "v0.0.0-20191119213627-4f8c1d86b1ba",
+)
+go_repository(
+ name = "org_golang_x_exp",
+ importpath = "golang.org/x/exp",
+ sum = "h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=",
+ version = "v0.0.0-20190121172915-509febef88a4",
+)
+go_repository(
+ name = "org_golang_x_lint",
+ importpath = "golang.org/x/lint",
+ sum = "h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=",
+ version = "v0.0.0-20190409202823-959b441ac422",
+)
+go_repository(
+ name = "org_golang_x_net",
+ importpath = "golang.org/x/net",
+ sum = "h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=",
+ version = "v0.0.0-20190503192946-f4e77d36d62c",
+)
+go_repository(
+ name = "org_golang_x_oauth2",
+ importpath = "golang.org/x/oauth2",
+ sum = "h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=",
+ version = "v0.0.0-20190604053449-0f29369cfe45",
+)
+go_repository(
+ name = "org_golang_x_sync",
+ importpath = "golang.org/x/sync",
+ sum = "h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=",
+ version = "v0.0.0-20190423024810-112230192c58",
+)
+go_repository(
+ name = "org_golang_x_sys",
+ importpath = "golang.org/x/sys",
+ sum = "h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=",
+ version = "v0.0.0-20190507160741-ecd444e8653b",
+)
+go_repository(
+ name = "org_golang_x_text",
+ importpath = "golang.org/x/text",
+ sum = "h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=",
+ version = "v0.3.2",
+)
+go_repository(
+ name = "org_golang_x_time",
+ importpath = "golang.org/x/time",
+ sum = "h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=",
+ version = "v0.0.0-20181108054448-85acf8d2951c",
+)
+go_repository(
+ name = "org_golang_x_tools",
+ importpath = "golang.org/x/tools",
+ sum = "h1:97SnQk1GYRXJgvwZ8fadnxDOWfKvkNQHH3CtZntPSrM=",
+ version = "v0.0.0-20190506145303-2d16b83fe98c",
+)
+go_repository(
+ name = "com_github_hashicorp_vault",
+ importpath = "github.com/hashicorp/vault",
+ tag = "v1.2.3",
+)
diff --git a/testing/go/aead_service.go b/testing/go/aead_service.go
new file mode 100644
index 0000000..548447b
--- /dev/null
+++ b/testing/go/aead_service.go
@@ -0,0 +1,71 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/aead"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// AEADService implements the Aead testing service.
+type AEADService struct {
+}
+
+func (s *AEADService) Encrypt(ctx context.Context, req *pb.AeadEncryptRequest) (*pb.AeadEncryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.AeadEncryptResponse{
+ Result: &pb.AeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := aead.New(handle)
+ if err != nil {
+ return &pb.AeadEncryptResponse{
+ Result: &pb.AeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ ciphertext, err := cipher.Encrypt(req.Plaintext, req.AssociatedData)
+ if err != nil {
+ return &pb.AeadEncryptResponse{
+ Result: &pb.AeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.AeadEncryptResponse{
+ Result: &pb.AeadEncryptResponse_Ciphertext{ciphertext}}, nil
+}
+
+func (s *AEADService) Decrypt(ctx context.Context, req *pb.AeadDecryptRequest) (*pb.AeadDecryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.AeadDecryptResponse{
+ Result: &pb.AeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := aead.New(handle)
+ if err != nil {
+ return &pb.AeadDecryptResponse{
+ Result: &pb.AeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ plaintext, err := cipher.Decrypt(req.Ciphertext, req.AssociatedData)
+ if err != nil {
+ return &pb.AeadDecryptResponse{
+ Result: &pb.AeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.AeadDecryptResponse{
+ Result: &pb.AeadDecryptResponse_Plaintext{plaintext}}, nil
+}
diff --git a/testing/go/daead_service.go b/testing/go/daead_service.go
new file mode 100644
index 0000000..b15b681
--- /dev/null
+++ b/testing/go/daead_service.go
@@ -0,0 +1,71 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/daead"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// DeterministicAEADService implements the DeterministicAead testing service.
+type DeterministicAEADService struct {
+}
+
+func (s *DeterministicAEADService) EncryptDeterministically(ctx context.Context, req *pb.DeterministicAeadEncryptRequest) (*pb.DeterministicAeadEncryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.DeterministicAeadEncryptResponse{
+ Result: &pb.DeterministicAeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := daead.New(handle)
+ if err != nil {
+ return &pb.DeterministicAeadEncryptResponse{
+ Result: &pb.DeterministicAeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ ciphertext, err := cipher.EncryptDeterministically(req.Plaintext, req.AssociatedData)
+ if err != nil {
+ return &pb.DeterministicAeadEncryptResponse{
+ Result: &pb.DeterministicAeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.DeterministicAeadEncryptResponse{
+ Result: &pb.DeterministicAeadEncryptResponse_Ciphertext{ciphertext}}, nil
+}
+
+func (s *DeterministicAEADService) DecryptDeterministically(ctx context.Context, req *pb.DeterministicAeadDecryptRequest) (*pb.DeterministicAeadDecryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.DeterministicAeadDecryptResponse{
+ Result: &pb.DeterministicAeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := daead.New(handle)
+ if err != nil {
+ return &pb.DeterministicAeadDecryptResponse{
+ Result: &pb.DeterministicAeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ plaintext, err := cipher.DecryptDeterministically(req.Ciphertext, req.AssociatedData)
+ if err != nil {
+ return &pb.DeterministicAeadDecryptResponse{
+ Result: &pb.DeterministicAeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.DeterministicAeadDecryptResponse{
+ Result: &pb.DeterministicAeadDecryptResponse_Plaintext{plaintext}}, nil
+}
diff --git a/testing/go/hybrid_service.go b/testing/go/hybrid_service.go
new file mode 100644
index 0000000..af1271e
--- /dev/null
+++ b/testing/go/hybrid_service.go
@@ -0,0 +1,71 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/hybrid"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// HybridService implements the Hybrid encryption and decryption testing service.
+type HybridService struct {
+}
+
+func (s *HybridService) Encrypt(ctx context.Context, req *pb.HybridEncryptRequest) (*pb.HybridEncryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.PublicKeyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.HybridEncryptResponse{
+ Result: &pb.HybridEncryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := hybrid.NewHybridEncrypt(handle)
+ if err != nil {
+ return &pb.HybridEncryptResponse{
+ Result: &pb.HybridEncryptResponse_Err{err.Error()}}, nil
+ }
+ ciphertext, err := cipher.Encrypt(req.Plaintext, req.ContextInfo)
+ if err != nil {
+ return &pb.HybridEncryptResponse{
+ Result: &pb.HybridEncryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.HybridEncryptResponse{
+ Result: &pb.HybridEncryptResponse_Ciphertext{ciphertext}}, nil
+}
+
+func (s *HybridService) Decrypt(ctx context.Context, req *pb.HybridDecryptRequest) (*pb.HybridDecryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.PrivateKeyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.HybridDecryptResponse{
+ Result: &pb.HybridDecryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := hybrid.NewHybridDecrypt(handle)
+ if err != nil {
+ return &pb.HybridDecryptResponse{
+ Result: &pb.HybridDecryptResponse_Err{err.Error()}}, nil
+ }
+ plaintext, err := cipher.Decrypt(req.Ciphertext, req.ContextInfo)
+ if err != nil {
+ return &pb.HybridDecryptResponse{
+ Result: &pb.HybridDecryptResponse_Err{err.Error()}}, nil
+ }
+ return &pb.HybridDecryptResponse{
+ Result: &pb.HybridDecryptResponse_Plaintext{plaintext}}, nil
+}
diff --git a/testing/go/keyset_service.go b/testing/go/keyset_service.go
new file mode 100644
index 0000000..39143e9
--- /dev/null
+++ b/testing/go/keyset_service.go
@@ -0,0 +1,112 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Package services is implements gRPC services for testing_api.
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+ tinkpb "github.com/google/tink/go/proto/tink_go_proto"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// KeysetService implements the Keyset testing service.
+type KeysetService struct {
+}
+
+func (s *KeysetService) Generate(ctx context.Context, req *pb.KeysetGenerateRequest) (*pb.KeysetGenerateResponse, error) {
+ template := &tinkpb.KeyTemplate{}
+ err := proto.Unmarshal(req.Template, template)
+ if err != nil {
+ return &pb.KeysetGenerateResponse{
+ Result: &pb.KeysetGenerateResponse_Err{err.Error()}}, nil
+ }
+ handle, err := keyset.NewHandle(template)
+ if err != nil {
+ return &pb.KeysetGenerateResponse{
+ Result: &pb.KeysetGenerateResponse_Err{err.Error()}}, nil
+ }
+ buf := new(bytes.Buffer)
+ writer := keyset.NewBinaryWriter(buf)
+ err = testkeyset.Write(handle, writer)
+ if err != nil {
+ return &pb.KeysetGenerateResponse{
+ Result: &pb.KeysetGenerateResponse_Err{err.Error()}}, nil
+ }
+ return &pb.KeysetGenerateResponse{
+ Result: &pb.KeysetGenerateResponse_Keyset{buf.Bytes()}}, nil
+}
+
+func (s *KeysetService) Public(ctx context.Context, req *pb.KeysetPublicRequest) (*pb.KeysetPublicResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.PrivateKeyset))
+ privateHandle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.KeysetPublicResponse{
+ Result: &pb.KeysetPublicResponse_Err{err.Error()}}, nil
+ }
+ publicHandle, err := privateHandle.Public()
+ if err != nil {
+ return &pb.KeysetPublicResponse{
+ Result: &pb.KeysetPublicResponse_Err{err.Error()}}, nil
+ }
+ buf := new(bytes.Buffer)
+ writer := keyset.NewBinaryWriter(buf)
+ err = testkeyset.Write(publicHandle, writer)
+ if err != nil {
+ return &pb.KeysetPublicResponse{
+ Result: &pb.KeysetPublicResponse_Err{err.Error()}}, nil
+ }
+ return &pb.KeysetPublicResponse{
+ Result: &pb.KeysetPublicResponse_PublicKeyset{buf.Bytes()}}, nil
+}
+
+func (s *KeysetService) ToJson(ctx context.Context, req *pb.KeysetToJsonRequest) (*pb.KeysetToJsonResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.KeysetToJsonResponse{
+ Result: &pb.KeysetToJsonResponse_Err{err.Error()}}, nil
+ }
+ buf := new(bytes.Buffer)
+ writer := keyset.NewJSONWriter(buf)
+ if err := testkeyset.Write(handle, writer); err != nil {
+ return &pb.KeysetToJsonResponse{
+ Result: &pb.KeysetToJsonResponse_Err{err.Error()}}, nil
+ }
+ return &pb.KeysetToJsonResponse{
+ Result: &pb.KeysetToJsonResponse_JsonKeyset{buf.String()}}, nil
+}
+
+func (s *KeysetService) FromJson(ctx context.Context, req *pb.KeysetFromJsonRequest) (*pb.KeysetFromJsonResponse, error) {
+ reader := keyset.NewJSONReader(bytes.NewBufferString(req.JsonKeyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.KeysetFromJsonResponse{
+ Result: &pb.KeysetFromJsonResponse_Err{err.Error()}}, nil
+ }
+ buf := new(bytes.Buffer)
+ writer := keyset.NewBinaryWriter(buf)
+ if err := testkeyset.Write(handle, writer); err != nil {
+ return &pb.KeysetFromJsonResponse{
+ Result: &pb.KeysetFromJsonResponse_Err{err.Error()}}, nil
+ }
+ return &pb.KeysetFromJsonResponse{
+ Result: &pb.KeysetFromJsonResponse_Keyset{buf.Bytes()}}, nil
+}
diff --git a/testing/go/mac_service.go b/testing/go/mac_service.go
new file mode 100644
index 0000000..ed733c4
--- /dev/null
+++ b/testing/go/mac_service.go
@@ -0,0 +1,67 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/mac"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// MacService implements the MAC testing service.
+type MacService struct {
+}
+
+func (s *MacService) ComputeMac(ctx context.Context, req *pb.ComputeMacRequest) (*pb.ComputeMacResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.ComputeMacResponse{
+ Result: &pb.ComputeMacResponse_Err{err.Error()}}, nil
+ }
+ primitive, err := mac.New(handle)
+ if err != nil {
+ return &pb.ComputeMacResponse{
+ Result: &pb.ComputeMacResponse_Err{err.Error()}}, nil
+ }
+ macValue, err := primitive.ComputeMAC(req.Data)
+ if err != nil {
+ return &pb.ComputeMacResponse{
+ Result: &pb.ComputeMacResponse_Err{err.Error()}}, nil
+ }
+ return &pb.ComputeMacResponse{
+ Result: &pb.ComputeMacResponse_MacValue{macValue}}, nil
+}
+
+func (s *MacService) VerifyMac(ctx context.Context, req *pb.VerifyMacRequest) (*pb.VerifyMacResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.VerifyMacResponse{Err: err.Error()}, nil
+ }
+ primitive, err := mac.New(handle)
+ if err != nil {
+ return &pb.VerifyMacResponse{Err: err.Error()}, nil
+ }
+ err = primitive.VerifyMAC(req.MacValue, req.Data)
+ if err != nil {
+ return &pb.VerifyMacResponse{Err: err.Error()}, nil
+ }
+ return &pb.VerifyMacResponse{}, nil
+}
diff --git a/testing/go/metadata_service.go b/testing/go/metadata_service.go
new file mode 100644
index 0000000..7fa0847
--- /dev/null
+++ b/testing/go/metadata_service.go
@@ -0,0 +1,31 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "context"
+
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// MetadataService implements the Keyset testing service.
+type MetadataService struct {
+}
+
+func (s *MetadataService) GetServerInfo(ctx context.Context, req *pb.ServerInfoRequest) (*pb.ServerInfoResponse, error) {
+ return &pb.ServerInfoResponse{
+ Language: "go",
+ }, nil
+}
diff --git a/testing/go/services_test.go b/testing/go/services_test.go
new file mode 100644
index 0000000..d863fff
--- /dev/null
+++ b/testing/go/services_test.go
@@ -0,0 +1,655 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services_test
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/google/tink/go/aead"
+ "github.com/google/tink/go/daead"
+ "github.com/google/tink/go/hybrid"
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/mac"
+ "github.com/google/tink/go/signature"
+ "github.com/google/tink/go/streamingaead"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+ "github.com/google/tink/testing/go/services"
+)
+
+func genKeyset(ctx context.Context, keysetService *services.KeysetService, template []byte) ([]byte, error) {
+ genRequest := &pb.KeysetGenerateRequest{Template: template}
+ genResponse, err := keysetService.Generate(ctx, genRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := genResponse.Result.(type) {
+ case *pb.KeysetGenerateResponse_Keyset:
+ return r.Keyset, nil
+ case *pb.KeysetGenerateResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("genResponse.Result has unexpected type %T", r)
+ }
+}
+
+func pubKeyset(ctx context.Context, keysetService *services.KeysetService, privateKeyset []byte) ([]byte, error) {
+ request := &pb.KeysetPublicRequest{PrivateKeyset: privateKeyset}
+ response, err := keysetService.Public(ctx, request)
+ if err != nil {
+ return nil, err
+ }
+ switch r := response.Result.(type) {
+ case *pb.KeysetPublicResponse_PublicKeyset:
+ return r.PublicKeyset, nil
+ case *pb.KeysetPublicResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("response.Result has unexpected type %T", r)
+ }
+}
+
+func keysetFromJSON(ctx context.Context, keysetService *services.KeysetService, jsonKeyset string) ([]byte, error) {
+ request := &pb.KeysetFromJsonRequest{JsonKeyset: jsonKeyset}
+ response, err := keysetService.FromJson(ctx, request)
+ if err != nil {
+ return nil, err
+ }
+ switch r := response.Result.(type) {
+ case *pb.KeysetFromJsonResponse_Keyset:
+ return r.Keyset, nil
+ case *pb.KeysetFromJsonResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("response.Result has unexpected type %T", r)
+ }
+}
+
+func keysetToJSON(ctx context.Context, keysetService *services.KeysetService, keyset []byte) (string, error) {
+ request := &pb.KeysetToJsonRequest{Keyset: keyset}
+ response, err := keysetService.ToJson(ctx, request)
+ if err != nil {
+ return "", err
+ }
+ switch r := response.Result.(type) {
+ case *pb.KeysetToJsonResponse_JsonKeyset:
+ return r.JsonKeyset, nil
+ case *pb.KeysetToJsonResponse_Err:
+ return "", errors.New(r.Err)
+ default:
+ return "", fmt.Errorf("response.Result has unexpected type %T", r)
+ }
+}
+
+func TestFromJSON(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ ctx := context.Background()
+ jsonKeyset := `
+ {
+ "primaryKeyId": 42,
+ "key": [
+ {
+ "keyData": {
+ "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
+ "keyMaterialType": "SYMMETRIC",
+ "value": "GhCS/1+ejWpx68NfGt6ziYHd"
+ },
+ "outputPrefixType": "TINK",
+ "keyId": 42,
+ "status": "ENABLED"
+ }
+ ]
+ }`
+ keysetData, err := keysetFromJSON(ctx, keysetService, jsonKeyset)
+ if err != nil {
+ t.Fatalf("keysetFromJSON failed: %v", err)
+ }
+ reader := keyset.NewBinaryReader(bytes.NewReader(keysetData))
+ keyset, err := reader.Read()
+ if err != nil {
+ t.Fatalf("reader.Read() failed: %v", err)
+ }
+ if keyset.GetPrimaryKeyId() != 42 {
+ t.Fatalf("Got keyset.GetPrimaryKeyId() == %d, want 42", keyset.GetPrimaryKeyId())
+ }
+}
+
+func TestGenerateToFromJSON(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(aead.AES128GCMKeyTemplate()) failed: %v", err)
+ }
+ keyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+ jsonKeyset, err := keysetToJSON(ctx, keysetService, keyset)
+ if err != nil {
+ t.Fatalf("keysetToJSON failed: %v", err)
+ }
+ output, err := keysetFromJSON(ctx, keysetService, jsonKeyset)
+ if err != nil {
+ t.Fatalf("keysetFromJSON failed: %v", err)
+ }
+ if bytes.Compare(output, keyset) != 0 {
+ t.Fatalf("output is %v, want %v", output, keyset)
+ }
+}
+
+func TestKeysetFromJSONFail(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ ctx := context.Background()
+ if _, err := keysetFromJSON(ctx, keysetService, "bad JSON"); err == nil {
+ t.Fatalf("keysetFromJSON from bad JSON succeeded unexpectedly.")
+ }
+}
+
+func TestKeysetToJSONFail(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ ctx := context.Background()
+ if _, err := keysetToJSON(ctx, keysetService, []byte("badKeyset")); err == nil {
+ t.Fatalf("keysetToJSON with bad keyset succeeded unexpectedly.")
+ }
+}
+
+func aeadEncrypt(ctx context.Context, aeadService *services.AEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
+ encRequest := &pb.AeadEncryptRequest{
+ Keyset: keyset,
+ Plaintext: plaintext,
+ AssociatedData: associatedData,
+ }
+ encResponse, err := aeadService.Encrypt(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := encResponse.Result.(type) {
+ case *pb.AeadEncryptResponse_Ciphertext:
+ return r.Ciphertext, nil
+ case *pb.AeadEncryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func aeadDecrypt(ctx context.Context, aeadService *services.AEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
+ decRequest := &pb.AeadDecryptRequest{
+ Keyset: keyset,
+ Ciphertext: ciphertext,
+ AssociatedData: associatedData,
+ }
+ decResponse, err := aeadService.Decrypt(ctx, decRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := decResponse.Result.(type) {
+ case *pb.AeadDecryptResponse_Plaintext:
+ return r.Plaintext, nil
+ case *pb.AeadDecryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func TestGenerateEncryptDecrypt(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ aeadService := &services.AEADService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(aead.AES128GCMKeyTemplate()) failed: %v", err)
+ }
+
+ keyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+
+ plaintext := []byte("The quick brown fox jumps over the lazy dog")
+ associatedData := []byte("Associated Data")
+ ciphertext, err := aeadEncrypt(ctx, aeadService, keyset, plaintext, associatedData)
+ if err != nil {
+ t.Fatalf("Aead Encrypt failed: %v", err)
+ }
+ output, err := aeadDecrypt(ctx, aeadService, keyset, ciphertext, associatedData)
+ if err != nil {
+ t.Fatalf("aeadDecrypt failed: %v", err)
+ }
+ if bytes.Compare(output, plaintext) != 0 {
+ t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
+ }
+
+ if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
+ t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
+ }
+ if _, err := aeadEncrypt(ctx, aeadService, []byte("badKeyset"), plaintext, associatedData); err == nil {
+ t.Fatalf("aeadEncrypt with bad keyset succeeded unexpectedly.")
+ }
+ if _, err := aeadDecrypt(ctx, aeadService, keyset, []byte("badCiphertext"), associatedData); err == nil {
+ t.Fatalf("aeadDecrypt of bad ciphertext succeeded unexpectedly.")
+ }
+}
+
+func daeadEncrypt(ctx context.Context, daeadService *services.DeterministicAEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
+ encRequest := &pb.DeterministicAeadEncryptRequest{
+ Keyset: keyset,
+ Plaintext: plaintext,
+ AssociatedData: associatedData,
+ }
+ encResponse, err := daeadService.EncryptDeterministically(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := encResponse.Result.(type) {
+ case *pb.DeterministicAeadEncryptResponse_Ciphertext:
+ return r.Ciphertext, nil
+ case *pb.DeterministicAeadEncryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func daeadDecrypt(ctx context.Context, daeadService *services.DeterministicAEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
+ decRequest := &pb.DeterministicAeadDecryptRequest{
+ Keyset: keyset,
+ Ciphertext: ciphertext,
+ AssociatedData: associatedData,
+ }
+ decResponse, err := daeadService.DecryptDeterministically(ctx, decRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := decResponse.Result.(type) {
+ case *pb.DeterministicAeadDecryptResponse_Plaintext:
+ return r.Plaintext, nil
+ case *pb.DeterministicAeadDecryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func TestGenerateEncryptDecryptDeterministically(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ daeadService := &services.DeterministicAEADService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(daead.AESSIVKeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(daead.AESSIVKeyTemplate()) failed: %v", err)
+ }
+
+ keyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+
+ plaintext := []byte("The quick brown fox jumps over the lazy dog")
+ associatedData := []byte("Associated Data")
+ ciphertext, err := daeadEncrypt(ctx, daeadService, keyset, plaintext, associatedData)
+ if err != nil {
+ t.Fatalf("Aead Encrypt failed: %v", err)
+ }
+ output, err := daeadDecrypt(ctx, daeadService, keyset, ciphertext, associatedData)
+ if err != nil {
+ t.Fatalf("daeadDecrypt failed: %v", err)
+ }
+ if bytes.Compare(output, plaintext) != 0 {
+ t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
+ }
+
+ if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
+ t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
+ }
+ if _, err := daeadEncrypt(ctx, daeadService, []byte("badKeyset"), plaintext, associatedData); err == nil {
+ t.Fatalf("daeadEncrypt with bad keyset succeeded unexpectedly.")
+ }
+ if _, err := daeadDecrypt(ctx, daeadService, keyset, []byte("badCiphertext"), associatedData); err == nil {
+ t.Fatalf("daeadDecrypt of bad ciphertext succeeded unexpectedly.")
+ }
+}
+
+func streamingAEADEncrypt(ctx context.Context, streamingAEADService *services.StreamingAEADService, keyset []byte, plaintext []byte, associatedData []byte) ([]byte, error) {
+ encRequest := &pb.StreamingAeadEncryptRequest{
+ Keyset: keyset,
+ Plaintext: plaintext,
+ AssociatedData: associatedData,
+ }
+ encResponse, err := streamingAEADService.Encrypt(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := encResponse.Result.(type) {
+ case *pb.StreamingAeadEncryptResponse_Ciphertext:
+ return r.Ciphertext, nil
+ case *pb.StreamingAeadEncryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func streamingAEADDecrypt(ctx context.Context, streamingAEADService *services.StreamingAEADService, keyset []byte, ciphertext []byte, associatedData []byte) ([]byte, error) {
+ decRequest := &pb.StreamingAeadDecryptRequest{
+ Keyset: keyset,
+ Ciphertext: ciphertext,
+ AssociatedData: associatedData,
+ }
+ decResponse, err := streamingAEADService.Decrypt(ctx, decRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := decResponse.Result.(type) {
+ case *pb.StreamingAeadDecryptResponse_Plaintext:
+ return r.Plaintext, nil
+ case *pb.StreamingAeadDecryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func TestGenerateEncryptDecryptStreaming(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ streamingAEADService := &services.StreamingAEADService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(streamingaead.AES128GCMHKDF4KBKeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(streamingaead.AES128GCMHKDF4KBKeyTemplate()) failed: %v", err)
+ }
+
+ keyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+
+ plaintext := []byte("The quick brown fox jumps over the lazy dog")
+ associatedData := []byte("Associated Data")
+ ciphertext, err := streamingAEADEncrypt(ctx, streamingAEADService, keyset, plaintext, associatedData)
+ if err != nil {
+ t.Fatalf("streamingAEADEncrypt failed: %v", err)
+ }
+ output, err := streamingAEADDecrypt(ctx, streamingAEADService, keyset, ciphertext, associatedData)
+ if err != nil {
+ t.Fatalf("streamingAEADDecrypt failed: %v", err)
+ }
+ if bytes.Compare(output, plaintext) != 0 {
+ t.Errorf("Decrypted ciphertext is %v, want %v", output, plaintext)
+ }
+
+ if _, err := genKeyset(ctx, keysetService, []byte("badTemplate")); err == nil {
+ t.Fatalf("genKeyset from bad template succeeded unexpectedly.")
+ }
+ if _, err := streamingAEADEncrypt(ctx, streamingAEADService, []byte("badKeyset"), plaintext, associatedData); err == nil {
+ t.Fatalf("streamingAEADEncrypt with bad keyset succeeded unexpectedly.")
+ }
+ if _, err := streamingAEADDecrypt(ctx, streamingAEADService, keyset, []byte("badCiphertext"), associatedData); err == nil {
+ t.Fatalf("streamingAEADDecrypt of bad ciphertext succeeded unexpectedly.")
+ }
+}
+
+func computeMAC(ctx context.Context, macService *services.MacService, keyset []byte, data []byte) ([]byte, error) {
+ encRequest := &pb.ComputeMacRequest{
+ Keyset: keyset,
+ Data: data,
+ }
+ response, err := macService.ComputeMac(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := response.Result.(type) {
+ case *pb.ComputeMacResponse_MacValue:
+ return r.MacValue, nil
+ case *pb.ComputeMacResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("response.Result has unexpected type %T", r)
+ }
+}
+
+func verifyMAC(ctx context.Context, macService *services.MacService, keyset []byte, macValue []byte, data []byte) error {
+ request := &pb.VerifyMacRequest{
+ Keyset: keyset,
+ MacValue: macValue,
+ Data: data,
+ }
+ response, err := macService.VerifyMac(ctx, request)
+ if err != nil {
+ return err
+ }
+ if response.Err != "" {
+ return errors.New(response.Err)
+ }
+ return nil
+}
+
+func TestComputeVerifyMac(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ macService := &services.MacService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(mac.HMACSHA256Tag128KeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(mac.HMACSHA256Tag128KeyTemplate()) failed: %v", err)
+ }
+
+ keyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+
+ data := []byte("The quick brown fox jumps over the lazy dog")
+ macValue, err := computeMAC(ctx, macService, keyset, data)
+ if err != nil {
+ t.Fatalf("computeMAC failed: %v", err)
+ }
+ if err := verifyMAC(ctx, macService, keyset, macValue, data); err != nil {
+ t.Fatalf("verifyMAC failed: %v", err)
+ }
+
+ if _, err := computeMAC(ctx, macService, []byte("badKeyset"), data); err == nil {
+ t.Fatalf("computeMAC with bad keyset succeeded unexpectedly.")
+ }
+ if err := verifyMAC(ctx, macService, keyset, []byte("badMacValue"), data); err == nil {
+ t.Fatalf("verifyMAC of bad MAC value succeeded unexpectedly.")
+ }
+}
+
+func hybridEncrypt(ctx context.Context, hybridService *services.HybridService, publicKeyset []byte, plaintext []byte, contextInfo []byte) ([]byte, error) {
+ encRequest := &pb.HybridEncryptRequest{
+ PublicKeyset: publicKeyset,
+ Plaintext: plaintext,
+ ContextInfo: contextInfo,
+ }
+ encResponse, err := hybridService.Encrypt(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := encResponse.Result.(type) {
+ case *pb.HybridEncryptResponse_Ciphertext:
+ return r.Ciphertext, nil
+ case *pb.HybridEncryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("encResponse.Result has unexpected type %T", r)
+ }
+}
+
+func hybridDecrypt(ctx context.Context, hybridService *services.HybridService, privateKeyset []byte, ciphertext []byte, contextInfo []byte) ([]byte, error) {
+ decRequest := &pb.HybridDecryptRequest{
+ PrivateKeyset: privateKeyset,
+ Ciphertext: ciphertext,
+ ContextInfo: contextInfo,
+ }
+ decResponse, err := hybridService.Decrypt(ctx, decRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := decResponse.Result.(type) {
+ case *pb.HybridDecryptResponse_Plaintext:
+ return r.Plaintext, nil
+ case *pb.HybridDecryptResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("decResponse.Result has unexpected type %T", r)
+ }
+}
+
+func TestHybridGenerateEncryptDecrypt(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ hybridService := &services.HybridService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(hybrid.ECIESHKDFAES128GCMKeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(hybrid.ECIESHKDFAES128GCMKeyTemplate()) failed: %v", err)
+ }
+
+ privateKeyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+ publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
+ if err != nil {
+ t.Fatalf("pubKeyset failed: %v", err)
+ }
+
+ plaintext := []byte("The quick brown fox jumps over the lazy dog")
+ associatedData := []byte("Associated Data")
+ ciphertext, err := hybridEncrypt(ctx, hybridService, publicKeyset, plaintext, associatedData)
+ if err != nil {
+ t.Fatalf("hybridEncrypt failed: %v", err)
+ }
+ output, err := hybridDecrypt(ctx, hybridService, privateKeyset, ciphertext, associatedData)
+ if err != nil {
+ t.Fatalf("hybridDecrypt failed: %v", err)
+ }
+ if bytes.Compare(output, plaintext) != 0 {
+ t.Fatalf("Decrypted ciphertext is %v, want %v", output, plaintext)
+ }
+
+ if _, err := pubKeyset(ctx, keysetService, []byte("badPrivateKeyset")); err == nil {
+ t.Fatalf("pubKeyset from bad private keyset succeeded unexpectedly.")
+ }
+ if _, err := hybridEncrypt(ctx, hybridService, []byte("badPublicKeyset"), plaintext, associatedData); err == nil {
+ t.Fatalf("hybridEncrypt with bad public keyset succeeded unexpectedly.")
+ }
+ if _, err := hybridDecrypt(ctx, hybridService, []byte("badPrivateKeyset"), ciphertext, associatedData); err == nil {
+ t.Fatalf("hybridDecrypt with bad private keyset succeeded unexpectedly.")
+ }
+ if _, err := hybridDecrypt(ctx, hybridService, privateKeyset, []byte("badCiphertext"), associatedData); err == nil {
+ t.Fatalf("hybridDecrypt of bad ciphertext succeeded unexpectedly.")
+ }
+}
+
+func signatureSign(ctx context.Context, signatureService *services.SignatureService, privateKeyset []byte, data []byte) ([]byte, error) {
+ encRequest := &pb.SignatureSignRequest{
+ PrivateKeyset: privateKeyset,
+ Data: data,
+ }
+ response, err := signatureService.Sign(ctx, encRequest)
+ if err != nil {
+ return nil, err
+ }
+ switch r := response.Result.(type) {
+ case *pb.SignatureSignResponse_Signature:
+ return r.Signature, nil
+ case *pb.SignatureSignResponse_Err:
+ return nil, errors.New(r.Err)
+ default:
+ return nil, fmt.Errorf("response.Result has unexpected type %T", r)
+ }
+}
+
+func signatureVerify(ctx context.Context, signatureService *services.SignatureService, publicKeyset []byte, signatureValue []byte, data []byte) error {
+ request := &pb.SignatureVerifyRequest{
+ PublicKeyset: publicKeyset,
+ Signature: signatureValue,
+ Data: data,
+ }
+ response, err := signatureService.Verify(ctx, request)
+ if err != nil {
+ return err
+ }
+ if response.Err != "" {
+ return errors.New(response.Err)
+ }
+ return nil
+}
+
+func TestSignatureSignVerify(t *testing.T) {
+ keysetService := &services.KeysetService{}
+ signatureService := &services.SignatureService{}
+ ctx := context.Background()
+
+ template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
+ if err != nil {
+ t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
+ }
+
+ privateKeyset, err := genKeyset(ctx, keysetService, template)
+ if err != nil {
+ t.Fatalf("genKeyset failed: %v", err)
+ }
+ publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
+ if err != nil {
+ t.Fatalf("pubKeyset failed: %v", err)
+ }
+
+ data := []byte("The quick brown fox jumps over the lazy dog")
+ signatureValue, err := signatureSign(ctx, signatureService, privateKeyset, data)
+ if err != nil {
+ t.Fatalf("signatureSign failed: %v", err)
+ }
+ if err := signatureVerify(ctx, signatureService, publicKeyset, signatureValue, data); err != nil {
+ t.Fatalf("signatureVerify failed: %v", err)
+ }
+
+ if _, err := signatureSign(ctx, signatureService, []byte("badPrivateKeyset"), data); err == nil {
+ t.Fatalf("signatureSign with bad private keyset succeeded unexpectedly.")
+ }
+ if err := signatureVerify(ctx, signatureService, publicKeyset, []byte("badSignature"), data); err == nil {
+ t.Fatalf("signatureVerify of bad signature succeeded unexpectedly.")
+ }
+ if err := signatureVerify(ctx, signatureService, []byte("badPublicKeyset"), signatureValue, data); err == nil {
+ t.Fatalf("signatureVerify of bad public keyset succeeded unexpectedly.")
+ }
+}
+
+func TestServerInfo(t *testing.T) {
+ metadataService := &services.MetadataService{}
+ ctx := context.Background()
+
+ req := &pb.ServerInfoRequest{}
+ rsp, err := metadataService.GetServerInfo(ctx, req)
+ if err != nil {
+ t.Fatalf("GetServerInfo failed: %v", err)
+ }
+ if strings.Compare(rsp.GetLanguage(), "go") != 0 {
+ t.Fatalf("Expected language 'go', got: %v", rsp.GetLanguage())
+ }
+}
diff --git a/testing/go/signature_service.go b/testing/go/signature_service.go
new file mode 100644
index 0000000..a756343
--- /dev/null
+++ b/testing/go/signature_service.go
@@ -0,0 +1,67 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/signature"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+// SignatureService implements the Signature testing service.
+type SignatureService struct {
+}
+
+func (s *SignatureService) Sign(ctx context.Context, req *pb.SignatureSignRequest) (*pb.SignatureSignResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.PrivateKeyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.SignatureSignResponse{
+ Result: &pb.SignatureSignResponse_Err{err.Error()}}, nil
+ }
+ signer, err := signature.NewSigner(handle)
+ if err != nil {
+ return &pb.SignatureSignResponse{
+ Result: &pb.SignatureSignResponse_Err{err.Error()}}, nil
+ }
+ sigValue, err := signer.Sign(req.Data)
+ if err != nil {
+ return &pb.SignatureSignResponse{
+ Result: &pb.SignatureSignResponse_Err{err.Error()}}, nil
+ }
+ return &pb.SignatureSignResponse{
+ Result: &pb.SignatureSignResponse_Signature{sigValue}}, nil
+}
+
+func (s *SignatureService) Verify(ctx context.Context, req *pb.SignatureVerifyRequest) (*pb.SignatureVerifyResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.PublicKeyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.SignatureVerifyResponse{Err: err.Error()}, nil
+ }
+ verifier, err := signature.NewVerifier(handle)
+ if err != nil {
+ return &pb.SignatureVerifyResponse{Err: err.Error()}, nil
+ }
+ err = verifier.Verify(req.Signature, req.Data)
+ if err != nil {
+ return &pb.SignatureVerifyResponse{Err: err.Error()}, nil
+ }
+ return &pb.SignatureVerifyResponse{}, nil
+}
diff --git a/testing/go/streaming_aead_service.go b/testing/go/streaming_aead_service.go
new file mode 100644
index 0000000..8956c21
--- /dev/null
+++ b/testing/go/streaming_aead_service.go
@@ -0,0 +1,111 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+package services
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/google/tink/go/keyset"
+ "github.com/google/tink/go/streamingaead"
+ "github.com/google/tink/go/testkeyset"
+ pb "github.com/google/tink/proto/testing/testing_api_go_grpc"
+)
+
+const (
+ decryptChunkSize = 2
+)
+
+// StreamingAEADService implements the StreamingAead testing service.
+type StreamingAEADService struct {
+}
+
+func (s *StreamingAEADService) Encrypt(ctx context.Context, req *pb.StreamingAeadEncryptRequest) (*pb.StreamingAeadEncryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := streamingaead.New(handle)
+ if err != nil {
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{err.Error()}}, nil
+ }
+ ciphertextBuf := &bytes.Buffer{}
+ w, err := cipher.NewEncryptingWriter(ciphertextBuf, req.AssociatedData)
+ if err != nil {
+ errMsg := fmt.Sprintf("cannot create an encrypt writer: %v", err)
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{errMsg}}, nil
+ }
+ n, err := w.Write(req.Plaintext)
+ if err != nil {
+ errMsg := fmt.Sprintf("error writing to an encrypt writer: %v", err)
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{errMsg}}, nil
+ }
+ if n != len(req.Plaintext) {
+ errMsg := fmt.Sprintf("unexpected number of bytes written. Got=%d;want=%d", n, len(req.Plaintext))
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{errMsg}}, nil
+ }
+ if err := w.Close(); err != nil {
+ errMsg := fmt.Sprintf("error closing writer: %v", err)
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Err{errMsg}}, nil
+ }
+ return &pb.StreamingAeadEncryptResponse{
+ Result: &pb.StreamingAeadEncryptResponse_Ciphertext{ciphertextBuf.Bytes()}}, nil
+}
+
+func (s *StreamingAEADService) Decrypt(ctx context.Context, req *pb.StreamingAeadDecryptRequest) (*pb.StreamingAeadDecryptResponse, error) {
+ reader := keyset.NewBinaryReader(bytes.NewReader(req.Keyset))
+ handle, err := testkeyset.Read(reader)
+ if err != nil {
+ return &pb.StreamingAeadDecryptResponse{
+ Result: &pb.StreamingAeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ cipher, err := streamingaead.New(handle)
+ if err != nil {
+ return &pb.StreamingAeadDecryptResponse{
+ Result: &pb.StreamingAeadDecryptResponse_Err{err.Error()}}, nil
+ }
+ r, err := cipher.NewDecryptingReader(bytes.NewBuffer(req.Ciphertext), req.AssociatedData)
+ if err != nil {
+ errMsg := fmt.Sprintf("cannot create an encrypt reader: %v", err)
+ return &pb.StreamingAeadDecryptResponse{
+ Result: &pb.StreamingAeadDecryptResponse_Err{errMsg}}, nil
+ }
+ plaintextBuf := &bytes.Buffer{}
+ var (
+ chunk = make([]byte, decryptChunkSize)
+ eof = false
+ )
+ for !eof {
+ n, err := r.Read(chunk)
+ if err != nil && err != io.EOF {
+ errMsg := fmt.Sprintf("error reading chunk: %v", err)
+ return &pb.StreamingAeadDecryptResponse{
+ Result: &pb.StreamingAeadDecryptResponse_Err{errMsg}}, nil
+ }
+ eof = err == io.EOF
+ plaintextBuf.Write(chunk[:n])
+ }
+ return &pb.StreamingAeadDecryptResponse{
+ Result: &pb.StreamingAeadDecryptResponse_Plaintext{plaintextBuf.Bytes()}}, nil
+}
diff --git a/testing/go/testing_server.go b/testing/go/testing_server.go
new file mode 100644
index 0000000..243c3bd
--- /dev/null
+++ b/testing/go/testing_server.go
@@ -0,0 +1,54 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Package main is implements an gRPC server for testing_api.
+package main
+
+import (
+ "fmt"
+ "log"
+ "net"
+
+ "flag"
+ // context is used to cancel outstanding requests
+ "google.golang.org/grpc"
+ pbgrpc "github.com/google/tink/proto/testing/testing_api_go_grpc"
+ "github.com/google/tink/testing/go/services"
+)
+
+var (
+ port = flag.Int("port", 10000, "The server port")
+)
+
+func main() {
+ flag.Parse()
+ lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
+ if err != nil {
+ log.Fatalf("Server failed to listen: %v", err)
+ }
+ log.Printf("Server is now listening on port: %d", *port)
+ server := grpc.NewServer()
+ if err != nil {
+ log.Fatalf("Failed to create new grpcprod server: %v", err)
+ }
+ pbgrpc.RegisterMetadataServer(server, &services.MetadataService{})
+ pbgrpc.RegisterKeysetServer(server, &services.KeysetService{})
+ pbgrpc.RegisterAeadServer(server, &services.AEADService{})
+ pbgrpc.RegisterDeterministicAeadServer(server, &services.DeterministicAEADService{})
+ pbgrpc.RegisterHybridServer(server, &services.HybridService{})
+ pbgrpc.RegisterMacServer(server, &services.MacService{})
+ pbgrpc.RegisterSignatureServer(server, &services.SignatureService{})
+ pbgrpc.RegisterStreamingAeadServer(server, &services.StreamingAEADService{})
+ server.Serve(lis)
+}
diff --git a/testing/java_src/.bazelversion b/testing/java_src/.bazelversion
new file mode 100644
index 0000000..fd2a018
--- /dev/null
+++ b/testing/java_src/.bazelversion
@@ -0,0 +1 @@
+3.1.0
diff --git a/testing/java_src/BUILD.bazel b/testing/java_src/BUILD.bazel
new file mode 100644
index 0000000..31d2263
--- /dev/null
+++ b/testing/java_src/BUILD.bazel
@@ -0,0 +1,121 @@
+load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library")
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+java_proto_library(
+ name = "testing_api_java_proto",
+ testonly = 1,
+ deps = ["@tink_base//proto/testing:testing_api_proto"],
+)
+
+java_grpc_library(
+ name = "testing_api_java_grpc",
+ testonly = 1,
+ srcs = ["@tink_base//proto/testing:testing_api_proto"],
+ deps = [":testing_api_java_proto"],
+)
+
+java_library(
+ name = "testing_services",
+ testonly = 1,
+ srcs = [
+ "java/com/google/crypto/tink/testing/AeadServiceImpl.java",
+ "java/com/google/crypto/tink/testing/DeterministicAeadServiceImpl.java",
+ "java/com/google/crypto/tink/testing/HybridServiceImpl.java",
+ "java/com/google/crypto/tink/testing/KeysetServiceImpl.java",
+ "java/com/google/crypto/tink/testing/MacServiceImpl.java",
+ "java/com/google/crypto/tink/testing/MetadataServiceImpl.java",
+ "java/com/google/crypto/tink/testing/SignatureServiceImpl.java",
+ "java/com/google/crypto/tink/testing/StreamingAeadServiceImpl.java",
+ ],
+ javacopts = JAVACOPTS_OSS,
+ deps = [
+ ":testing_api_java_grpc",
+ ":testing_api_java_proto",
+ "@com_google_protobuf//:protobuf_java",
+ "@io_grpc_grpc_java//api",
+ "@io_grpc_grpc_java//protobuf",
+ "@io_grpc_grpc_java//stub",
+ "@tink_java//:cleartext_keyset_handle",
+ "@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "@tink_java//src/main/java/com/google/crypto/tink:core",
+ "@tink_java//src/main/java/com/google/crypto/tink:primitives",
+ ],
+)
+
+java_binary(
+ name = "testing_server",
+ testonly = 1,
+ srcs = [
+ "java/com/google/crypto/tink/testing/TestingServer.java",
+ ],
+ javacopts = JAVACOPTS_OSS,
+ main_class = "com.google.crypto.tink.testing.TestingServer",
+ runtime_deps = [
+ "@io_grpc_grpc_java//netty",
+ ],
+ deps = [
+ ":testing_services",
+ "@io_grpc_grpc_java//api",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
+ ],
+)
+
+java_test(
+ name = "TestingServicesTest",
+ size = "small",
+ srcs = [
+ "javatests/com/google/crypto/tink/testing/TestingServicesTest.java",
+ ],
+ deps = [
+ ":testing_api_java_grpc",
+ ":testing_api_java_proto",
+ ":testing_services",
+ "@com_google_protobuf//:protobuf_java",
+ "@com_google_protobuf//:protobuf_java_util",
+ "@io_grpc_grpc_java//api",
+ "@io_grpc_grpc_java//core:inprocess",
+ "@io_grpc_grpc_java//protobuf",
+ "@io_grpc_grpc_java//stub",
+ "@io_grpc_grpc_java//testing",
+ "@maven//:com_google_truth_truth",
+ "@maven//:junit_junit",
+ "@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink:core",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aead_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
+ "@tink_java//src/main/java/com/google/crypto/tink/daead:deterministic_aead_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/mac:mac_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_key_templates",
+ ],
+)
+
+java_test(
+ name = "AsymmetricTestingServicesTest",
+ size = "small",
+ srcs = [
+ "javatests/com/google/crypto/tink/testing/AsymmetricTestingServicesTest.java",
+ ],
+ deps = [
+ ":testing_api_java_grpc",
+ ":testing_api_java_proto",
+ ":testing_services",
+ "@com_google_protobuf//:protobuf_java",
+ "@com_google_protobuf//:protobuf_java_util",
+ "@io_grpc_grpc_java//api",
+ "@io_grpc_grpc_java//core:inprocess",
+ "@io_grpc_grpc_java//protobuf",
+ "@io_grpc_grpc_java//stub",
+ "@io_grpc_grpc_java//testing",
+ "@maven//:com_google_truth_truth",
+ "@maven//:junit_junit",
+ "@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
+ "@tink_java//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/signature:signature_key_templates",
+ ],
+)
diff --git a/testing/java_src/WORKSPACE b/testing/java_src/WORKSPACE
new file mode 100644
index 0000000..0f98e36
--- /dev/null
+++ b/testing/java_src/WORKSPACE
@@ -0,0 +1,37 @@
+workspace(name = "testing_java")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "tink_base",
+ path = "../..",
+)
+
+local_repository(
+ name = "tink_java",
+ path = "../../java_src",
+)
+
+load("@tink_base//:tink_base_deps.bzl", "tink_base_deps")
+tink_base_deps()
+
+load("@tink_base//:tink_base_deps_init.bzl", "tink_base_deps_init")
+tink_base_deps_init()
+
+load("@tink_java//:tink_java_deps.bzl", "tink_java_deps")
+tink_java_deps()
+
+load("@tink_java//:tink_java_deps_init.bzl", "tink_java_deps_init")
+tink_java_deps_init()
+
+http_archive(
+ name = "io_grpc_grpc_java",
+ sha256 = "446ad7a2e85bbd05406dbf95232c7c49ed90de83b3b60cb2048b0c4c9f254d29",
+ strip_prefix = "grpc-java-1.29.0",
+ url = "https://github.com/grpc/grpc-java/archive/v1.29.0.zip",
+)
+
+load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories")
+
+grpc_java_repositories()
+
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/AeadServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/AeadServiceImpl.java
new file mode 100644
index 0000000..db45012
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/AeadServiceImpl.java
@@ -0,0 +1,88 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.proto.testing.AeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.AeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.AeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.AeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.AeadGrpc.AeadImplBase;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC Aead Testing service. */
+public final class AeadServiceImpl extends AeadImplBase {
+
+ public AeadServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Encrypts a message. */
+ @Override
+ public void encrypt(
+ AeadEncryptRequest request, StreamObserver<AeadEncryptResponse> responseObserver) {
+ AeadEncryptResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ Aead aead = keysetHandle.getPrimitive(Aead.class);
+ byte[] ciphertext =
+ aead.encrypt(
+ request.getPlaintext().toByteArray(), request.getAssociatedData().toByteArray());
+ response =
+ AeadEncryptResponse.newBuilder().setCiphertext(ByteString.copyFrom(ciphertext)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = AeadEncryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Decrypts a message. */
+ @Override
+ public void decrypt(
+ AeadDecryptRequest request, StreamObserver<AeadDecryptResponse> responseObserver) {
+ AeadDecryptResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ Aead aead = keysetHandle.getPrimitive(Aead.class);
+ byte[] plaintext =
+ aead.decrypt(
+ request.getCiphertext().toByteArray(), request.getAssociatedData().toByteArray());
+ response =
+ AeadDecryptResponse.newBuilder().setPlaintext(ByteString.copyFrom(plaintext)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = AeadDecryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/DeterministicAeadServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/DeterministicAeadServiceImpl.java
new file mode 100644
index 0000000..249b0eb
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/DeterministicAeadServiceImpl.java
@@ -0,0 +1,94 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.DeterministicAead;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.proto.testing.DeterministicAeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.DeterministicAeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.DeterministicAeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.DeterministicAeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.DeterministicAeadGrpc.DeterministicAeadImplBase;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC DeterministicAead Testing service. */
+public final class DeterministicAeadServiceImpl extends DeterministicAeadImplBase {
+
+ public DeterministicAeadServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Encrypts a message. */
+ @Override
+ public void encryptDeterministically(
+ DeterministicAeadEncryptRequest request,
+ StreamObserver<DeterministicAeadEncryptResponse> responseObserver) {
+ DeterministicAeadEncryptResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ DeterministicAead daead = keysetHandle.getPrimitive(DeterministicAead.class);
+ byte[] ciphertext =
+ daead.encryptDeterministically(
+ request.getPlaintext().toByteArray(), request.getAssociatedData().toByteArray());
+ response =
+ DeterministicAeadEncryptResponse.newBuilder()
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = DeterministicAeadEncryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Decrypts a message. */
+ @Override
+ public void decryptDeterministically(
+ DeterministicAeadDecryptRequest request,
+ StreamObserver<DeterministicAeadDecryptResponse> responseObserver) {
+ DeterministicAeadDecryptResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ DeterministicAead daead = keysetHandle.getPrimitive(DeterministicAead.class);
+ byte[] plaintext =
+ daead.decryptDeterministically(
+ request.getCiphertext().toByteArray(), request.getAssociatedData().toByteArray());
+ response =
+ DeterministicAeadDecryptResponse.newBuilder()
+ .setPlaintext(ByteString.copyFrom(plaintext))
+ .build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = DeterministicAeadDecryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/HybridServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/HybridServiceImpl.java
new file mode 100644
index 0000000..0952bf3
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/HybridServiceImpl.java
@@ -0,0 +1,89 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.HybridDecrypt;
+import com.google.crypto.tink.HybridEncrypt;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.proto.testing.HybridDecryptRequest;
+import com.google.crypto.tink.proto.testing.HybridDecryptResponse;
+import com.google.crypto.tink.proto.testing.HybridEncryptRequest;
+import com.google.crypto.tink.proto.testing.HybridEncryptResponse;
+import com.google.crypto.tink.proto.testing.HybridGrpc.HybridImplBase;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC Hybrid Encryption Testing service. */
+public final class HybridServiceImpl extends HybridImplBase {
+
+ public HybridServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Encrypts a message. */
+ @Override
+ public void encrypt(
+ HybridEncryptRequest request, StreamObserver<HybridEncryptResponse> responseObserver) {
+ HybridEncryptResponse response;
+ try {
+ KeysetHandle publicKeysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getPublicKeyset().toByteArray()));
+ HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class);
+ byte[] ciphertext =
+ hybridEncrypt.encrypt(
+ request.getPlaintext().toByteArray(), request.getContextInfo().toByteArray());
+ response =
+ HybridEncryptResponse.newBuilder().setCiphertext(ByteString.copyFrom(ciphertext)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = HybridEncryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Decrypts a message. */
+ @Override
+ public void decrypt(
+ HybridDecryptRequest request, StreamObserver<HybridDecryptResponse> responseObserver) {
+ HybridDecryptResponse response;
+ try {
+ KeysetHandle privateKeysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getPrivateKeyset().toByteArray()));
+ HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class);
+ byte[] plaintext =
+ hybridDecrypt.decrypt(
+ request.getCiphertext().toByteArray(), request.getContextInfo().toByteArray());
+ response =
+ HybridDecryptResponse.newBuilder().setPlaintext(ByteString.copyFrom(plaintext)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = HybridDecryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/KeysetServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/KeysetServiceImpl.java
new file mode 100644
index 0000000..86c126f
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/KeysetServiceImpl.java
@@ -0,0 +1,173 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.BinaryKeysetWriter;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.JsonKeysetReader;
+import com.google.crypto.tink.JsonKeysetWriter;
+import com.google.crypto.tink.KeyTemplate;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.proto.Keyset;
+import com.google.crypto.tink.proto.OutputPrefixType;
+import com.google.crypto.tink.proto.testing.KeysetFromJsonRequest;
+import com.google.crypto.tink.proto.testing.KeysetFromJsonResponse;
+import com.google.crypto.tink.proto.testing.KeysetGenerateRequest;
+import com.google.crypto.tink.proto.testing.KeysetGenerateResponse;
+import com.google.crypto.tink.proto.testing.KeysetGrpc.KeysetImplBase;
+import com.google.crypto.tink.proto.testing.KeysetPublicRequest;
+import com.google.crypto.tink.proto.testing.KeysetPublicResponse;
+import com.google.crypto.tink.proto.testing.KeysetToJsonRequest;
+import com.google.crypto.tink.proto.testing.KeysetToJsonResponse;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.ExtensionRegistryLite;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implement a gRPC Keyset Testing service. */
+public final class KeysetServiceImpl extends KeysetImplBase {
+
+ public KeysetServiceImpl() throws GeneralSecurityException {
+ }
+
+ @Override
+ public void generate(
+ KeysetGenerateRequest request, StreamObserver<KeysetGenerateResponse> responseObserver) {
+ KeysetGenerateResponse response;
+ try {
+ com.google.crypto.tink.proto.KeyTemplate protoTemplate =
+ com.google.crypto.tink.proto.KeyTemplate.parseFrom(
+ request.getTemplate(), ExtensionRegistryLite.getEmptyRegistry());
+ KeyTemplate template =
+ KeyTemplate.create(
+ protoTemplate.getTypeUrl(),
+ protoTemplate.getValue().toByteArray(),
+ convertOutputPrefixTypeFromProto(protoTemplate.getOutputPrefixType()));
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(template);
+ Keyset keyset = CleartextKeysetHandle.getKeyset(keysetHandle);
+ ByteArrayOutputStream keysetStream = new ByteArrayOutputStream();
+ BinaryKeysetWriter.withOutputStream(keysetStream).write(keyset);
+ keysetStream.close();
+ response =
+ KeysetGenerateResponse.newBuilder()
+ .setKeyset(ByteString.copyFrom(keysetStream.toByteArray()))
+ .build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = KeysetGenerateResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void public_(
+ KeysetPublicRequest request, StreamObserver<KeysetPublicResponse> responseObserver) {
+ KeysetPublicResponse response;
+ try {
+ KeysetHandle privateKeysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getPrivateKeyset().toByteArray()));
+ KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();
+ Keyset publicKeyset = CleartextKeysetHandle.getKeyset(publicKeysetHandle);
+ ByteArrayOutputStream publicKeysetStream = new ByteArrayOutputStream();
+ BinaryKeysetWriter.withOutputStream(publicKeysetStream).write(publicKeyset);
+ publicKeysetStream.close();
+ response =
+ KeysetPublicResponse.newBuilder()
+ .setPublicKeyset(ByteString.copyFrom(publicKeysetStream.toByteArray()))
+ .build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = KeysetPublicResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void toJson(
+ KeysetToJsonRequest request, StreamObserver<KeysetToJsonResponse> responseObserver) {
+ KeysetToJsonResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ Keyset keyset = CleartextKeysetHandle.getKeyset(keysetHandle);
+ ByteArrayOutputStream jsonKeysetStream = new ByteArrayOutputStream();
+ JsonKeysetWriter.withOutputStream(jsonKeysetStream).write(keyset);
+ jsonKeysetStream.close();
+ response =
+ KeysetToJsonResponse.newBuilder().setJsonKeyset(jsonKeysetStream.toString()).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = KeysetToJsonResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void fromJson(
+ KeysetFromJsonRequest request, StreamObserver<KeysetFromJsonResponse> responseObserver) {
+ KeysetFromJsonResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(JsonKeysetReader.withString(request.getJsonKeyset()));
+ Keyset keyset = CleartextKeysetHandle.getKeyset(keysetHandle);
+ ByteArrayOutputStream keysetStream = new ByteArrayOutputStream();
+ BinaryKeysetWriter.withOutputStream(keysetStream).write(keyset);
+ keysetStream.close();
+ response =
+ KeysetFromJsonResponse.newBuilder()
+ .setKeyset(ByteString.copyFrom(keysetStream.toByteArray()))
+ .build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = KeysetFromJsonResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ private static KeyTemplate.OutputPrefixType convertOutputPrefixTypeFromProto(
+ OutputPrefixType outputPrefixType) {
+ switch (outputPrefixType) {
+ case TINK:
+ return KeyTemplate.OutputPrefixType.TINK;
+ case LEGACY:
+ return KeyTemplate.OutputPrefixType.LEGACY;
+ case RAW:
+ return KeyTemplate.OutputPrefixType.RAW;
+ case CRUNCHY:
+ return KeyTemplate.OutputPrefixType.CRUNCHY;
+ default:
+ throw new IllegalArgumentException("Unknown output prefix type");
+ }
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/MacServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/MacServiceImpl.java
new file mode 100644
index 0000000..2892cb8
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/MacServiceImpl.java
@@ -0,0 +1,84 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.Mac;
+import com.google.crypto.tink.proto.testing.ComputeMacRequest;
+import com.google.crypto.tink.proto.testing.ComputeMacResponse;
+import com.google.crypto.tink.proto.testing.MacGrpc.MacImplBase;
+import com.google.crypto.tink.proto.testing.VerifyMacRequest;
+import com.google.crypto.tink.proto.testing.VerifyMacResponse;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC MAC Testing service. */
+public final class MacServiceImpl extends MacImplBase {
+
+ public MacServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Encrypts a message. */
+ @Override
+ public void computeMac(
+ ComputeMacRequest request,
+ StreamObserver<ComputeMacResponse> responseObserver) {
+ ComputeMacResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+ byte[] macValue = mac.computeMac(request.getData().toByteArray());
+ response = ComputeMacResponse.newBuilder().setMacValue(ByteString.copyFrom(macValue)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = ComputeMacResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Decrypts a message. */
+ @Override
+ public void verifyMac(
+ VerifyMacRequest request,
+ StreamObserver<VerifyMacResponse> responseObserver) {
+ VerifyMacResponse response;
+ try {
+ KeysetHandle keysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+ mac.verifyMac(request.getMacValue().toByteArray(), request.getData().toByteArray());
+ response = VerifyMacResponse.getDefaultInstance();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = VerifyMacResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/MetadataServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/MetadataServiceImpl.java
new file mode 100644
index 0000000..b1a74bd
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/MetadataServiceImpl.java
@@ -0,0 +1,41 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.Version;
+import com.google.crypto.tink.proto.testing.MetadataGrpc.MetadataImplBase;
+import com.google.crypto.tink.proto.testing.ServerInfoRequest;
+import com.google.crypto.tink.proto.testing.ServerInfoResponse;
+import io.grpc.stub.StreamObserver;
+import java.security.GeneralSecurityException;
+
+/** Implement a gRPC service for the server's metadata. */
+public final class MetadataServiceImpl extends MetadataImplBase {
+
+ public MetadataServiceImpl() throws GeneralSecurityException {
+ }
+
+ @Override
+ public void getServerInfo(
+ ServerInfoRequest request, StreamObserver<ServerInfoResponse> responseObserver) {
+ ServerInfoResponse response =
+ ServerInfoResponse.newBuilder()
+ .setLanguage("java")
+ .setTinkVersion(Version.TINK_VERSION)
+ .build();
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/SignatureServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/SignatureServiceImpl.java
new file mode 100644
index 0000000..976577d
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/SignatureServiceImpl.java
@@ -0,0 +1,85 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.PublicKeySign;
+import com.google.crypto.tink.PublicKeyVerify;
+import com.google.crypto.tink.proto.testing.SignatureGrpc.SignatureImplBase;
+import com.google.crypto.tink.proto.testing.SignatureSignRequest;
+import com.google.crypto.tink.proto.testing.SignatureSignResponse;
+import com.google.crypto.tink.proto.testing.SignatureVerifyRequest;
+import com.google.crypto.tink.proto.testing.SignatureVerifyResponse;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC Signature Testing service. */
+public final class SignatureServiceImpl extends SignatureImplBase {
+
+ public SignatureServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Signs a message. */
+ @Override
+ public void sign(
+ SignatureSignRequest request,
+ StreamObserver<SignatureSignResponse> responseObserver) {
+ SignatureSignResponse response;
+ try {
+ KeysetHandle privateKeysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getPrivateKeyset().toByteArray()));
+ PublicKeySign signer = privateKeysetHandle.getPrimitive(PublicKeySign.class);
+ byte[] signatureValue = signer.sign(request.getData().toByteArray());
+ response = SignatureSignResponse.newBuilder().setSignature(ByteString.copyFrom(signatureValue)).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = SignatureSignResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Verifies a signature. */
+ @Override
+ public void verify(
+ SignatureVerifyRequest request,
+ StreamObserver<SignatureVerifyResponse> responseObserver) {
+ SignatureVerifyResponse response;
+ try {
+ KeysetHandle publicKeysetHandle =
+ CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getPublicKeyset().toByteArray()));
+ PublicKeyVerify verifier = publicKeysetHandle.getPrimitive(PublicKeyVerify.class);
+ verifier.verify(request.getSignature().toByteArray(), request.getData().toByteArray());
+ response = SignatureVerifyResponse.getDefaultInstance();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = SignatureVerifyResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/StreamingAeadServiceImpl.java b/testing/java_src/java/com/google/crypto/tink/testing/StreamingAeadServiceImpl.java
new file mode 100644
index 0000000..68ae63d
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/StreamingAeadServiceImpl.java
@@ -0,0 +1,107 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.CleartextKeysetHandle;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.StreamingAead;
+import com.google.crypto.tink.proto.testing.StreamingAeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.StreamingAeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.StreamingAeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.StreamingAeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.StreamingAeadGrpc.StreamingAeadImplBase;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+
+/** Implements a gRPC StreamingAead Testing service. */
+public final class StreamingAeadServiceImpl extends StreamingAeadImplBase {
+
+ public StreamingAeadServiceImpl() throws GeneralSecurityException {
+ }
+
+ /** Encrypts a message. */
+ @Override
+ public void encrypt(
+ StreamingAeadEncryptRequest request,
+ StreamObserver<StreamingAeadEncryptResponse> responseObserver) {
+ StreamingAeadEncryptResponse response;
+ try {
+ KeysetHandle keysetHandle = CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ StreamingAead streamingAead = keysetHandle.getPrimitive(StreamingAead.class);
+
+ ByteArrayOutputStream ciphertextStream = new ByteArrayOutputStream();
+ try (OutputStream encryptingStream =
+ streamingAead.newEncryptingStream(
+ ciphertextStream, request.getAssociatedData().toByteArray())) {
+ request.getPlaintext().writeTo(encryptingStream);
+ }
+ response =
+ StreamingAeadEncryptResponse.newBuilder()
+ .setCiphertext(ByteString.copyFrom(ciphertextStream.toByteArray()))
+ .build();
+
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = StreamingAeadEncryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ responseObserver.onError(Status.UNKNOWN.withDescription(e.getMessage()).asException());
+ return;
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+
+ /** Decrypts a message. */
+ @Override
+ public void decrypt(
+ StreamingAeadDecryptRequest request,
+ StreamObserver<StreamingAeadDecryptResponse> responseObserver) {
+ StreamingAeadDecryptResponse response;
+ try {
+ KeysetHandle keysetHandle = CleartextKeysetHandle.read(
+ BinaryKeysetReader.withBytes(request.getKeyset().toByteArray()));
+ StreamingAead streamingAead = keysetHandle.getPrimitive(StreamingAead.class);
+
+ InputStream ciphertextStream = request.getCiphertext().newInput();
+ InputStream decryptingStream = streamingAead.newDecryptingStream(
+ ciphertextStream, request.getAssociatedData().toByteArray());
+ ByteArrayOutputStream plaintextStream = new ByteArrayOutputStream();
+ while (true) {
+ int bytesRead = decryptingStream.read();
+ if (bytesRead == -1) {
+ break;
+ }
+ plaintextStream.write(bytesRead);
+ }
+
+ response = StreamingAeadDecryptResponse.newBuilder().setPlaintext(
+ ByteString.copyFrom(plaintextStream.toByteArray())).build();
+ } catch (GeneralSecurityException | InvalidProtocolBufferException e) {
+ response = StreamingAeadDecryptResponse.newBuilder().setErr(e.toString()).build();
+ } catch (IOException e) {
+ response = StreamingAeadDecryptResponse.newBuilder().setErr(e.toString()).build();
+ }
+ responseObserver.onNext(response);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/testing/java_src/java/com/google/crypto/tink/testing/TestingServer.java b/testing/java_src/java/com/google/crypto/tink/testing/TestingServer.java
new file mode 100644
index 0000000..4e3e667
--- /dev/null
+++ b/testing/java_src/java/com/google/crypto/tink/testing/TestingServer.java
@@ -0,0 +1,58 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+
+
+import com.google.crypto.tink.config.TinkConfig;
+import io.grpc.ServerBuilder;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/**
+ * Starts a server with Tink testing services.
+ */
+public final class TestingServer {
+
+ private TestingServer() {
+ // no instances
+ }
+
+ public static void main(String[] args)
+ throws InterruptedException, GeneralSecurityException, IOException {
+
+ if ((args.length != 2) || !args[0].equals("--port")) {
+ System.out.println("Usage: TestingServer --port <port>");
+ System.exit(1);
+ }
+ int port = Integer.parseInt(args[1]);
+
+ TinkConfig.register();
+
+ System.out.println("Start server on port " + port);
+ ServerBuilder.forPort(port)
+ .addService(new MetadataServiceImpl())
+ .addService(new KeysetServiceImpl())
+ .addService(new AeadServiceImpl())
+ .addService(new DeterministicAeadServiceImpl())
+ .addService(new StreamingAeadServiceImpl())
+ .addService(new HybridServiceImpl())
+ .addService(new MacServiceImpl())
+ .addService(new SignatureServiceImpl())
+ .build()
+ .start()
+ .awaitTermination();
+ }
+}
diff --git a/testing/java_src/javatests/com/google/crypto/tink/testing/AsymmetricTestingServicesTest.java b/testing/java_src/javatests/com/google/crypto/tink/testing/AsymmetricTestingServicesTest.java
new file mode 100644
index 0000000..c7dab0b
--- /dev/null
+++ b/testing/java_src/javatests/com/google/crypto/tink/testing/AsymmetricTestingServicesTest.java
@@ -0,0 +1,310 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import com.google.crypto.tink.config.TinkConfig;
+import com.google.crypto.tink.hybrid.HybridKeyTemplates;
+import com.google.crypto.tink.proto.testing.HybridDecryptRequest;
+import com.google.crypto.tink.proto.testing.HybridDecryptResponse;
+import com.google.crypto.tink.proto.testing.HybridEncryptRequest;
+import com.google.crypto.tink.proto.testing.HybridEncryptResponse;
+import com.google.crypto.tink.proto.testing.HybridGrpc;
+import com.google.crypto.tink.proto.testing.KeysetGenerateRequest;
+import com.google.crypto.tink.proto.testing.KeysetGenerateResponse;
+import com.google.crypto.tink.proto.testing.KeysetGrpc;
+import com.google.crypto.tink.proto.testing.KeysetPublicRequest;
+import com.google.crypto.tink.proto.testing.KeysetPublicResponse;
+import com.google.crypto.tink.proto.testing.SignatureGrpc;
+import com.google.crypto.tink.proto.testing.SignatureSignRequest;
+import com.google.crypto.tink.proto.testing.SignatureSignResponse;
+import com.google.crypto.tink.proto.testing.SignatureVerifyRequest;
+import com.google.crypto.tink.proto.testing.SignatureVerifyResponse;
+import com.google.crypto.tink.signature.SignatureKeyTemplates;
+import com.google.protobuf.ByteString;
+import io.grpc.ManagedChannel;
+import io.grpc.Server;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AsymmetricTestingServicesTest {
+ private Server server;
+ private ManagedChannel channel;
+ KeysetGrpc.KeysetBlockingStub keysetStub;
+ HybridGrpc.HybridBlockingStub hybridStub;
+ SignatureGrpc.SignatureBlockingStub signatureStub;
+
+
+ @Before
+ public void setUp() throws Exception {
+ TinkConfig.register();
+ String serverName = InProcessServerBuilder.generateName();
+ server = InProcessServerBuilder
+ .forName(serverName)
+ .directExecutor()
+ .addService(new KeysetServiceImpl())
+ .addService(new HybridServiceImpl())
+ .addService(new SignatureServiceImpl())
+ .build()
+ .start();
+ channel = InProcessChannelBuilder
+ .forName(serverName)
+ .directExecutor()
+ .build();
+ keysetStub = KeysetGrpc.newBlockingStub(channel);
+ hybridStub = HybridGrpc.newBlockingStub(channel);
+ signatureStub = SignatureGrpc.newBlockingStub(channel);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ assertThat(channel.shutdown().awaitTermination(5, SECONDS)).isTrue();
+ assertThat(server.shutdown().awaitTermination(5, SECONDS)).isTrue();
+ }
+
+ private static KeysetGenerateResponse generateKeyset(
+ KeysetGrpc.KeysetBlockingStub keysetStub, byte[] template) {
+ KeysetGenerateRequest genRequest =
+ KeysetGenerateRequest.newBuilder().setTemplate(ByteString.copyFrom(template)).build();
+ return keysetStub.generate(genRequest);
+ }
+
+ private static KeysetPublicResponse publicKeyset(
+ KeysetGrpc.KeysetBlockingStub keysetStub, byte[] privateKeyset) {
+ KeysetPublicRequest request =
+ KeysetPublicRequest.newBuilder()
+ .setPrivateKeyset(ByteString.copyFrom(privateKeyset))
+ .build();
+ return keysetStub.public_(request);
+ }
+
+ private static HybridEncryptResponse hybridEncrypt(
+ HybridGrpc.HybridBlockingStub hybridStub,
+ byte[] publicKeyset,
+ byte[] plaintext,
+ byte[] contextInfo) {
+ HybridEncryptRequest encRequest =
+ HybridEncryptRequest.newBuilder()
+ .setPublicKeyset(ByteString.copyFrom(publicKeyset))
+ .setPlaintext(ByteString.copyFrom(plaintext))
+ .setContextInfo(ByteString.copyFrom(contextInfo))
+ .build();
+ return hybridStub.encrypt(encRequest);
+ }
+
+ private static HybridDecryptResponse hybridDecrypt(
+ HybridGrpc.HybridBlockingStub hybridStub,
+ byte[] privateKeyset,
+ byte[] ciphertext,
+ byte[] contextInfo) {
+ HybridDecryptRequest decRequest =
+ HybridDecryptRequest.newBuilder()
+ .setPrivateKeyset(ByteString.copyFrom(privateKeyset))
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .setContextInfo(ByteString.copyFrom(contextInfo))
+ .build();
+ return hybridStub.decrypt(decRequest);
+ }
+
+ @Test
+ public void hybridGenerateEncryptDecrypt_success() throws Exception {
+ byte[] template = HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template);
+ assertThat(genResponse.getErr()).isEmpty();
+ byte[] privateKeyset = genResponse.getKeyset().toByteArray();
+
+ KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset);
+ assertThat(pubResponse.getErr()).isEmpty();
+ byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray();
+
+ HybridEncryptResponse encResponse =
+ hybridEncrypt(hybridStub, publicKeyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ HybridDecryptResponse decResponse =
+ hybridDecrypt(hybridStub, privateKeyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isEmpty();
+ byte[] output = decResponse.getPlaintext().toByteArray();
+
+ assertThat(output).isEqualTo(plaintext);
+ }
+
+ @Test
+ public void publicKeyset_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ KeysetPublicResponse response = publicKeyset(keysetStub, badKeyset);
+ assertThat(response.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void hybridEncrypt_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] contextInfo = "hybrid_encrypt_bad_keyset".getBytes(UTF_8);
+ HybridEncryptResponse encResponse =
+ hybridEncrypt(hybridStub, badKeyset, plaintext, contextInfo);
+ assertThat(encResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void hybridDecrypt_failsOnBadCiphertext() throws Exception {
+ byte[] template = HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM.toByteArray();
+ byte[] badCiphertext = "bad ciphertext".getBytes(UTF_8);
+ byte[] contextInfo = "hybrid_decrypt_bad_ciphertext".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] privateKeyset = keysetResponse.getKeyset().toByteArray();
+
+ KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset);
+ assertThat(pubResponse.getErr()).isEmpty();
+ byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray();
+
+ HybridDecryptResponse decResponse =
+ hybridDecrypt(hybridStub, publicKeyset, badCiphertext, contextInfo);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void hybridDecrypt_failsOnBadKeyset() throws Exception {
+ byte[] template = HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] contextInfo = "hybrid_decrypt_bad_keyset".getBytes(UTF_8);
+
+ KeysetGenerateResponse privateKeysetResponse = generateKeyset(keysetStub, template);
+ assertThat(privateKeysetResponse.getErr()).isEmpty();
+ byte[] privateKeyset = privateKeysetResponse.getKeyset().toByteArray();
+
+ KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset);
+ assertThat(pubResponse.getErr()).isEmpty();
+ byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray();
+
+ HybridEncryptResponse encResponse =
+ hybridEncrypt(hybridStub, publicKeyset, plaintext, contextInfo);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ HybridDecryptResponse decResponse =
+ hybridDecrypt(hybridStub, badKeyset, ciphertext, contextInfo);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ private static SignatureSignResponse signatureSign(
+ SignatureGrpc.SignatureBlockingStub signatureStub, byte[] privateKeyset, byte[] data) {
+ SignatureSignRequest request =
+ SignatureSignRequest.newBuilder()
+ .setPrivateKeyset(ByteString.copyFrom(privateKeyset))
+ .setData(ByteString.copyFrom(data))
+ .build();
+ return signatureStub.sign(request);
+ }
+
+ private static SignatureVerifyResponse signatureVerify(
+ SignatureGrpc.SignatureBlockingStub signatureStub,
+ byte[] publicKeyset,
+ byte[] signature,
+ byte[] data) {
+ SignatureVerifyRequest request =
+ SignatureVerifyRequest.newBuilder()
+ .setPublicKeyset(ByteString.copyFrom(publicKeyset))
+ .setSignature(ByteString.copyFrom(signature))
+ .setData(ByteString.copyFrom(data))
+ .build();
+ return signatureStub.verify(request);
+ }
+
+ @Test
+ public void signatureSignVerify_success() throws Exception {
+ byte[] template = SignatureKeyTemplates.ECDSA_P256.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template);
+ assertThat(genResponse.getErr()).isEmpty();
+ byte[] privateKeyset = genResponse.getKeyset().toByteArray();
+
+ KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset);
+ assertThat(pubResponse.getErr()).isEmpty();
+ byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray();
+
+ SignatureSignResponse signResponse = signatureSign(signatureStub, privateKeyset, data);
+ assertThat(signResponse.getErr()).isEmpty();
+ byte[] signature = signResponse.getSignature().toByteArray();
+
+ SignatureVerifyResponse verifyResponse =
+ signatureVerify(signatureStub, publicKeyset, signature, data);
+ assertThat(verifyResponse.getErr()).isEmpty();
+ }
+
+ @Test
+ public void signatureSign_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ SignatureSignResponse response = signatureSign(signatureStub, badKeyset, data);
+ assertThat(response.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void signatureVerify_failsOnBadSignature() throws Exception {
+ byte[] template = SignatureKeyTemplates.ECDSA_P256.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template);
+ assertThat(genResponse.getErr()).isEmpty();
+ byte[] privateKeyset = genResponse.getKeyset().toByteArray();
+
+ KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset);
+ assertThat(pubResponse.getErr()).isEmpty();
+ byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray();
+
+ SignatureVerifyResponse verifyResponse =
+ signatureVerify(signatureStub, publicKeyset, "bad signature".getBytes(UTF_8), data);
+ assertThat(verifyResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void signatureVerify_failsOnBadKeyset() throws Exception {
+ byte[] template = SignatureKeyTemplates.ECDSA_P256.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template);
+ assertThat(genResponse.getErr()).isEmpty();
+ byte[] privateKeyset = genResponse.getKeyset().toByteArray();
+
+ SignatureSignResponse signResponse = signatureSign(signatureStub, privateKeyset, data);
+ assertThat(signResponse.getErr()).isEmpty();
+ byte[] signature = signResponse.getSignature().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ SignatureVerifyResponse verifyResponse =
+ signatureVerify(signatureStub, badKeyset, signature, data);
+ assertThat(verifyResponse.getErr()).isNotEmpty();
+ }
+
+}
diff --git a/testing/java_src/javatests/com/google/crypto/tink/testing/TestingServicesTest.java b/testing/java_src/javatests/com/google/crypto/tink/testing/TestingServicesTest.java
new file mode 100644
index 0000000..80289dc
--- /dev/null
+++ b/testing/java_src/javatests/com/google/crypto/tink/testing/TestingServicesTest.java
@@ -0,0 +1,555 @@
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.crypto.tink.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import com.google.crypto.tink.BinaryKeysetReader;
+import com.google.crypto.tink.aead.AeadKeyTemplates;
+import com.google.crypto.tink.config.TinkConfig;
+import com.google.crypto.tink.daead.DeterministicAeadKeyTemplates;
+import com.google.crypto.tink.mac.MacKeyTemplates;
+import com.google.crypto.tink.proto.Keyset;
+import com.google.crypto.tink.proto.testing.AeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.AeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.AeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.AeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.AeadGrpc;
+import com.google.crypto.tink.proto.testing.ComputeMacRequest;
+import com.google.crypto.tink.proto.testing.ComputeMacResponse;
+import com.google.crypto.tink.proto.testing.DeterministicAeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.DeterministicAeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.DeterministicAeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.DeterministicAeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.DeterministicAeadGrpc;
+import com.google.crypto.tink.proto.testing.KeysetFromJsonRequest;
+import com.google.crypto.tink.proto.testing.KeysetFromJsonResponse;
+import com.google.crypto.tink.proto.testing.KeysetGenerateRequest;
+import com.google.crypto.tink.proto.testing.KeysetGenerateResponse;
+import com.google.crypto.tink.proto.testing.KeysetGrpc;
+import com.google.crypto.tink.proto.testing.KeysetToJsonRequest;
+import com.google.crypto.tink.proto.testing.KeysetToJsonResponse;
+import com.google.crypto.tink.proto.testing.MacGrpc;
+import com.google.crypto.tink.proto.testing.MetadataGrpc;
+import com.google.crypto.tink.proto.testing.ServerInfoRequest;
+import com.google.crypto.tink.proto.testing.ServerInfoResponse;
+import com.google.crypto.tink.proto.testing.StreamingAeadDecryptRequest;
+import com.google.crypto.tink.proto.testing.StreamingAeadDecryptResponse;
+import com.google.crypto.tink.proto.testing.StreamingAeadEncryptRequest;
+import com.google.crypto.tink.proto.testing.StreamingAeadEncryptResponse;
+import com.google.crypto.tink.proto.testing.StreamingAeadGrpc;
+import com.google.crypto.tink.proto.testing.VerifyMacRequest;
+import com.google.crypto.tink.proto.testing.VerifyMacResponse;
+import com.google.crypto.tink.streamingaead.StreamingAeadKeyTemplates;
+import com.google.protobuf.ByteString;
+import io.grpc.ManagedChannel;
+import io.grpc.Server;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class TestingServicesTest {
+ private Server server;
+ private ManagedChannel channel;
+ MetadataGrpc.MetadataBlockingStub metadataStub;
+ KeysetGrpc.KeysetBlockingStub keysetStub;
+ AeadGrpc.AeadBlockingStub aeadStub;
+ DeterministicAeadGrpc.DeterministicAeadBlockingStub daeadStub;
+ StreamingAeadGrpc.StreamingAeadBlockingStub streamingAeadStub;
+ MacGrpc.MacBlockingStub macStub;
+
+ @Before
+ public void setUp() throws Exception {
+ TinkConfig.register();
+ String serverName = InProcessServerBuilder.generateName();
+ server = InProcessServerBuilder
+ .forName(serverName)
+ .directExecutor()
+ .addService(new MetadataServiceImpl())
+ .addService(new KeysetServiceImpl())
+ .addService(new AeadServiceImpl())
+ .addService(new DeterministicAeadServiceImpl())
+ .addService(new StreamingAeadServiceImpl())
+ .addService(new MacServiceImpl())
+ .build()
+ .start();
+ channel = InProcessChannelBuilder
+ .forName(serverName)
+ .directExecutor()
+ .build();
+ metadataStub = MetadataGrpc.newBlockingStub(channel);
+ keysetStub = KeysetGrpc.newBlockingStub(channel);
+ aeadStub = AeadGrpc.newBlockingStub(channel);
+ daeadStub = DeterministicAeadGrpc.newBlockingStub(channel);
+ streamingAeadStub = StreamingAeadGrpc.newBlockingStub(channel);
+ macStub = MacGrpc.newBlockingStub(channel);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ assertThat(channel.shutdown().awaitTermination(5, SECONDS)).isTrue();
+ assertThat(server.shutdown().awaitTermination(5, SECONDS)).isTrue();
+ }
+
+ private static KeysetGenerateResponse generateKeyset(
+ KeysetGrpc.KeysetBlockingStub keysetStub, byte[] template) {
+ KeysetGenerateRequest genRequest =
+ KeysetGenerateRequest.newBuilder().setTemplate(ByteString.copyFrom(template)).build();
+ return keysetStub.generate(genRequest);
+ }
+
+ private static KeysetToJsonResponse keysetToJson(
+ KeysetGrpc.KeysetBlockingStub keysetStub, byte[] keyset) {
+ KeysetToJsonRequest request =
+ KeysetToJsonRequest.newBuilder().setKeyset(ByteString.copyFrom(keyset)).build();
+ return keysetStub.toJson(request);
+ }
+
+ private static KeysetFromJsonResponse keysetFromJson(
+ KeysetGrpc.KeysetBlockingStub keysetStub, String jsonKeyset) {
+ KeysetFromJsonRequest request =
+ KeysetFromJsonRequest.newBuilder().setJsonKeyset(jsonKeyset).build();
+ return keysetStub.fromJson(request);
+ }
+
+ @Test
+ public void toJson_success() throws Exception {
+ String jsonKeyset =
+ ""
+ + "{"
+ + " \"primaryKeyId\": 42,"
+ + " \"key\": ["
+ + " {"
+ + " \"keyData\": {"
+ + " \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesGcmKey\","
+ + " \"keyMaterialType\": \"SYMMETRIC\","
+ + " \"value\": \"AFakeTestKeyValue1234567\""
+ + " },"
+ + " \"outputPrefixType\": \"TINK\","
+ + " \"keyId\": 42,"
+ + " \"status\": \"ENABLED\""
+ + " }"
+ + " ]"
+ + "})";
+ KeysetFromJsonResponse fromResponse = keysetFromJson(keysetStub, jsonKeyset);
+ assertThat(fromResponse.getErr()).isEmpty();
+ byte[] output = fromResponse.getKeyset().toByteArray();
+
+ Keyset keyset = BinaryKeysetReader.withBytes(output).read();
+ assertThat(keyset.getPrimaryKeyId()).isEqualTo(42);
+ }
+
+ @Test
+ public void toFromJson_success() throws Exception {
+ byte[] template = AeadKeyTemplates.AES128_GCM.toByteArray();
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ KeysetToJsonResponse toResponse = keysetToJson(keysetStub, keyset);
+ assertThat(toResponse.getErr()).isEmpty();
+ String jsonKeyset = toResponse.getJsonKeyset();
+
+ KeysetFromJsonResponse fromResponse = keysetFromJson(keysetStub, jsonKeyset);
+ assertThat(fromResponse.getErr()).isEmpty();
+ byte[] output = fromResponse.getKeyset().toByteArray();
+
+ assertThat(output).isEqualTo(keyset);
+ }
+
+ private static AeadEncryptResponse aeadEncrypt(
+ AeadGrpc.AeadBlockingStub aeadStub, byte[] keyset, byte[] plaintext, byte[] associatedData) {
+ AeadEncryptRequest encRequest =
+ AeadEncryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setPlaintext(ByteString.copyFrom(plaintext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return aeadStub.encrypt(encRequest);
+ }
+
+ private static AeadDecryptResponse aeadDecrypt(
+ AeadGrpc.AeadBlockingStub aeadStub, byte[] keyset, byte[] ciphertext, byte[] associatedData) {
+ AeadDecryptRequest decRequest =
+ AeadDecryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return aeadStub.decrypt(decRequest);
+ }
+
+ @Test
+ public void aeadGenerateEncryptDecrypt_success() throws Exception {
+ byte[] template = AeadKeyTemplates.AES128_GCM.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ AeadEncryptResponse encResponse = aeadEncrypt(aeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ AeadDecryptResponse decResponse = aeadDecrypt(aeadStub, keyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isEmpty();
+ byte[] output = decResponse.getPlaintext().toByteArray();
+
+ assertThat(output).isEqualTo(plaintext);
+ }
+
+ @Test
+ public void generateKeyset_failsOnBadTemplate() throws Exception {
+ byte[] badTemplate = "bad template".getBytes(UTF_8);
+ KeysetGenerateResponse genResponse = generateKeyset(keysetStub, badTemplate);
+ assertThat(genResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void aeadEncrypt_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "aead_encrypt_fails_on_bad_keyset".getBytes(UTF_8);
+ AeadEncryptResponse encResponse = aeadEncrypt(aeadStub, badKeyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void aeadDecrypt_failsOnBadCiphertext() throws Exception {
+ byte[] template = AeadKeyTemplates.AES128_GCM.toByteArray();
+ byte[] badCiphertext = "bad ciphertext".getBytes(UTF_8);
+ byte[] associatedData = "aead_decrypt_fails_on_bad_ciphertext".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ AeadDecryptResponse decResponse = aeadDecrypt(aeadStub, keyset, badCiphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void aeadDecrypt_failsOnBadKeyset() throws Exception {
+ byte[] template = AeadKeyTemplates.AES128_GCM.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ AeadEncryptResponse encResponse = aeadEncrypt(aeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+
+ AeadDecryptResponse decResponse = aeadDecrypt(aeadStub, badKeyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ private static DeterministicAeadEncryptResponse daeadEncrypt(
+ DeterministicAeadGrpc.DeterministicAeadBlockingStub daeadStub,
+ byte[] keyset,
+ byte[] plaintext,
+ byte[] associatedData) {
+ DeterministicAeadEncryptRequest encRequest =
+ DeterministicAeadEncryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setPlaintext(ByteString.copyFrom(plaintext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return daeadStub.encryptDeterministically(encRequest);
+ }
+
+ private static DeterministicAeadDecryptResponse daeadDecrypt(
+ DeterministicAeadGrpc.DeterministicAeadBlockingStub daeadStub,
+ byte[] keyset,
+ byte[] ciphertext,
+ byte[] associatedData) {
+ DeterministicAeadDecryptRequest decRequest =
+ DeterministicAeadDecryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return daeadStub.decryptDeterministically(decRequest);
+ }
+
+ @Test
+ public void daeadGenerateEncryptDecryptDeterministically_success() throws Exception {
+ byte[] template = DeterministicAeadKeyTemplates.AES256_SIV.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ DeterministicAeadEncryptResponse encResponse =
+ daeadEncrypt(daeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ DeterministicAeadDecryptResponse decResponse =
+ daeadDecrypt(daeadStub, keyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isEmpty();
+ byte[] output = decResponse.getPlaintext().toByteArray();
+
+ assertThat(output).isEqualTo(plaintext);
+ }
+
+ @Test
+ public void daeadEncryptDeterministically_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "aead_encrypt_fails_on_bad_keyset".getBytes(UTF_8);
+ DeterministicAeadEncryptResponse encResponse =
+ daeadEncrypt(daeadStub, badKeyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void daeadDecryptDeterministically_failsOnBadCiphertext() throws Exception {
+ byte[] template = DeterministicAeadKeyTemplates.AES256_SIV.toByteArray();
+ byte[] badCiphertext = "bad ciphertext".getBytes(UTF_8);
+ byte[] associatedData = "aead_decrypt_fails_on_bad_ciphertext".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ DeterministicAeadDecryptResponse decResponse =
+ daeadDecrypt(daeadStub, keyset, badCiphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void daeadDecryptDeterministically_failsOnBadKeyset() throws Exception {
+ byte[] template = DeterministicAeadKeyTemplates.AES256_SIV.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ DeterministicAeadEncryptResponse encResponse =
+ daeadEncrypt(daeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+
+ DeterministicAeadDecryptResponse decResponse =
+ daeadDecrypt(daeadStub, badKeyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ private static StreamingAeadEncryptResponse streamingAeadEncrypt(
+ StreamingAeadGrpc.StreamingAeadBlockingStub streamingAeadStub,
+ byte[] keyset,
+ byte[] plaintext,
+ byte[] associatedData) {
+ StreamingAeadEncryptRequest encRequest =
+ StreamingAeadEncryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setPlaintext(ByteString.copyFrom(plaintext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return streamingAeadStub.encrypt(encRequest);
+ }
+
+ private static StreamingAeadDecryptResponse streamingAeadDecrypt(
+ StreamingAeadGrpc.StreamingAeadBlockingStub streamingAeadStub,
+ byte[] keyset,
+ byte[] ciphertext,
+ byte[] associatedData) {
+ StreamingAeadDecryptRequest decRequest =
+ StreamingAeadDecryptRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setCiphertext(ByteString.copyFrom(ciphertext))
+ .setAssociatedData(ByteString.copyFrom(associatedData))
+ .build();
+ return streamingAeadStub.decrypt(decRequest);
+ }
+
+ @Test
+ public void streamingAeadGenerateEncryptDecrypt_success() throws Exception {
+ byte[] template = StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ StreamingAeadEncryptResponse encResponse = streamingAeadEncrypt(
+ streamingAeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ StreamingAeadDecryptResponse decResponse = streamingAeadDecrypt(
+ streamingAeadStub, keyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isEmpty();
+ byte[] output = decResponse.getPlaintext().toByteArray();
+
+ assertThat(output).isEqualTo(plaintext);
+ }
+
+ @Test
+ public void streamingAeadEncrypt_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "streamingAead_encrypt_fails_on_bad_keyset".getBytes(UTF_8);
+ StreamingAeadEncryptResponse encResponse = streamingAeadEncrypt(
+ streamingAeadStub, badKeyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void streamingAeadDecrypt_failsOnBadCiphertext() throws Exception {
+ byte[] template = StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB.toByteArray();
+ byte[] badCiphertext = "bad ciphertext".getBytes(UTF_8);
+ byte[] associatedData = "streamingAead_decrypt_fails_on_bad_ciphertext".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ StreamingAeadDecryptResponse decResponse = streamingAeadDecrypt(
+ streamingAeadStub, keyset, badCiphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void streamingAeadDecrypt_failsOnBadKeyset() throws Exception {
+ byte[] template = StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB.toByteArray();
+ byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+ byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ StreamingAeadEncryptResponse encResponse = streamingAeadEncrypt(
+ streamingAeadStub, keyset, plaintext, associatedData);
+ assertThat(encResponse.getErr()).isEmpty();
+ byte[] ciphertext = encResponse.getCiphertext().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+
+ StreamingAeadDecryptResponse decResponse = streamingAeadDecrypt(
+ streamingAeadStub, badKeyset, ciphertext, associatedData);
+ assertThat(decResponse.getErr()).isNotEmpty();
+ }
+
+ private static ComputeMacResponse computeMac(
+ MacGrpc.MacBlockingStub macStub, byte[] keyset, byte[] data) {
+ ComputeMacRequest request =
+ ComputeMacRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setData(ByteString.copyFrom(data))
+ .build();
+ return macStub.computeMac(request);
+ }
+
+ private static VerifyMacResponse verifyMac(
+ MacGrpc.MacBlockingStub macStub, byte[] keyset, byte[] macValue, byte[] data) {
+ VerifyMacRequest request =
+ VerifyMacRequest.newBuilder()
+ .setKeyset(ByteString.copyFrom(keyset))
+ .setMacValue(ByteString.copyFrom(macValue))
+ .setData(ByteString.copyFrom(data))
+ .build();
+ return macStub.verifyMac(request);
+ }
+
+ @Test
+ public void computeVerifyMac_success() throws Exception {
+ byte[] template = MacKeyTemplates.HMAC_SHA256_128BITTAG.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ ComputeMacResponse compResponse = computeMac(macStub, keyset, data);
+ assertThat(compResponse.getErr()).isEmpty();
+ byte[] macValue = compResponse.getMacValue().toByteArray();
+
+ VerifyMacResponse verifyResponse = verifyMac(macStub, keyset, macValue, data);
+ assertThat(verifyResponse.getErr()).isEmpty();
+ }
+
+ @Test
+ public void computeMac_failsOnBadKeyset() throws Exception {
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ ComputeMacResponse compResponse = computeMac(macStub, badKeyset, data);
+ assertThat(compResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void verifyMac_failsOnBadMacValue() throws Exception {
+ byte[] template = MacKeyTemplates.HMAC_SHA256_128BITTAG.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ VerifyMacResponse verifyResponse =
+ verifyMac(macStub, keyset, "bad mac_value".getBytes(UTF_8), data);
+ assertThat(verifyResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void verifyMac_failsOnBadKeyset() throws Exception {
+ byte[] template = MacKeyTemplates.HMAC_SHA256_128BITTAG.toByteArray();
+ byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8);
+
+ KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template);
+ assertThat(keysetResponse.getErr()).isEmpty();
+ byte[] keyset = keysetResponse.getKeyset().toByteArray();
+
+ ComputeMacResponse compResponse = computeMac(macStub, keyset, data);
+ assertThat(compResponse.getErr()).isEmpty();
+ byte[] macValue = compResponse.getMacValue().toByteArray();
+
+ byte[] badKeyset = "bad keyset".getBytes(UTF_8);
+ VerifyMacResponse verifyResponse = verifyMac(macStub, badKeyset, macValue, data);
+ assertThat(verifyResponse.getErr()).isNotEmpty();
+ }
+
+ @Test
+ public void getServerInfo_success() throws Exception {
+ ServerInfoResponse response =
+ metadataStub.getServerInfo(ServerInfoRequest.getDefaultInstance());
+ assertThat(response.getLanguage()).isEqualTo("java");
+ assertThat(response.getTinkVersion()).isNotEmpty();
+ }
+}
diff --git a/testing/python/.bazelversion b/testing/python/.bazelversion
new file mode 100644
index 0000000..fd2a018
--- /dev/null
+++ b/testing/python/.bazelversion
@@ -0,0 +1 @@
+3.1.0
diff --git a/testing/python/BUILD.bazel b/testing/python/BUILD.bazel
new file mode 100644
index 0000000..ecabedf
--- /dev/null
+++ b/testing/python/BUILD.bazel
@@ -0,0 +1,69 @@
+load("@rules_proto_grpc//python:defs.bzl", "python_grpc_library")
+load("@rules_python//python:defs.bzl", "py_binary", "py_library")
+load("@tink_py_pip_deps//:requirements.bzl", "requirement")
+
+package(
+ default_testonly = 1,
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"])
+
+python_grpc_library(
+ name = "testing_api_python_library",
+ deps = ["@tink_base//proto/testing:testing_api_proto"],
+)
+
+py_library(
+ name = "services",
+ srcs = ["services.py"],
+ srcs_version = "PY3",
+ deps = [
+ ":testing_api_python_library",
+ "@com_google_protobuf//:protobuf_python",
+ "@tink_py//tink:cleartext_keyset_handle",
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/signature",
+ ],
+)
+
+py_test(
+ name = "services_test",
+ srcs = ["services_test.py"],
+ python_version = "PY3",
+ srcs_version = "PY3",
+ deps = [
+ ":services",
+ ":testing_api_python_library",
+ requirement("absl-py"),
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/signature",
+ ],
+)
+
+py_binary(
+ name = "testing_server",
+ srcs = ["testing_server.py"],
+ python_version = "PY3",
+ srcs_version = "PY3",
+ deps = [
+ ":services",
+ ":testing_api_python_library",
+ "@com_google_protobuf//:protobuf_python",
+ "@tink_py//tink:cleartext_keyset_handle",
+ "@tink_py//tink:tink_python",
+ "@tink_py//tink/aead",
+ "@tink_py//tink/daead",
+ "@tink_py//tink/hybrid",
+ "@tink_py//tink/mac",
+ "@tink_py//tink/signature",
+ ],
+)
diff --git a/testing/python/WORKSPACE b/testing/python/WORKSPACE
new file mode 100644
index 0000000..31d3ee8
--- /dev/null
+++ b/testing/python/WORKSPACE
@@ -0,0 +1,89 @@
+workspace(name = "testing_python")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "tink_base",
+ path = "../..",
+)
+
+local_repository(
+ name = "tink_py",
+ path = "../../python",
+)
+
+local_repository(
+ name = "tink_cc",
+ path = "../../cc",
+)
+
+# NOTE: The Python dependencies have to be loaded first, as they rely on a
+# newer version of rules_python.
+load("@tink_py//:tink_py_deps.bzl", "tink_py_deps")
+tink_py_deps()
+
+load("@tink_py//:tink_py_deps_init.bzl", "tink_py_deps_init")
+tink_py_deps_init("tink_py")
+
+load("@tink_py_pip_deps//:requirements.bzl", tink_pip_install = "pip_install")
+tink_pip_install()
+
+load("@tink_base//:tink_base_deps.bzl", "tink_base_deps")
+tink_base_deps()
+
+load("@tink_base//:tink_base_deps_init.bzl", "tink_base_deps_init")
+tink_base_deps_init()
+
+load("@tink_cc//:tink_cc_deps.bzl", "tink_cc_deps")
+tink_cc_deps()
+
+load("@tink_cc//:tink_cc_deps_init.bzl", "tink_cc_deps_init")
+tink_cc_deps_init()
+
+http_archive(
+ name = "rules_python",
+ strip_prefix = "rules_python-94677401bc56ed5d756f50b441a6a5c7f735a6d4",
+ url = "https://github.com/bazelbuild/rules_python/archive/94677401bc56ed5d756f50b441a6a5c7f735a6d4.zip",
+ sha256 = "de39bc4d6605e6d395faf5e07516c64c8d833404ee3eb132b5ff1161f9617dec",
+)
+
+http_archive(
+ name = "rules_proto_grpc",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+)
+
+load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos")
+rules_proto_grpc_toolchains()
+rules_proto_grpc_repos()
+
+load("@rules_proto_grpc//python:repositories.bzl", rules_proto_grpc_python_repos="python_repos")
+rules_proto_grpc_python_repos()
+
+load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
+
+grpc_deps()
+
+load("@rules_python//python:repositories.bzl", "py_repositories")
+py_repositories()
+
+load("@rules_python//python:pip.bzl", "pip_repositories", "pip3_import")
+pip_repositories()
+
+pip3_import(
+ name = "pip_deps",
+ requirements = "//:requirements.txt",
+)
+
+load("@pip_deps//:requirements.bzl", "pip_install")
+pip_install()
+
+pip3_import(
+ name = "rules_proto_grpc_py3_deps",
+ requirements = "@rules_proto_grpc//python:requirements.txt",
+)
+
+load("@rules_proto_grpc_py3_deps//:requirements.bzl", pip3_install="pip_install")
+pip3_install()
+
diff --git a/testing/python/external/portpicker.BUILD.bazel b/testing/python/external/portpicker.BUILD.bazel
new file mode 100644
index 0000000..57e2ec3
--- /dev/null
+++ b/testing/python/external/portpicker.BUILD.bazel
@@ -0,0 +1,13 @@
+# Description:
+# Import of portpicker library.
+
+licenses(["notice"])
+
+exports_files(["LICENSE"])
+
+py_library(
+ name = "portpicker",
+ srcs = glob(["*.py"]),
+ srcs_version = "PY2AND3",
+ visibility = ["//visibility:public"],
+)
diff --git a/testing/python/requirements.txt b/testing/python/requirements.txt
new file mode 100644
index 0000000..b998a06
--- /dev/null
+++ b/testing/python/requirements.txt
@@ -0,0 +1 @@
+absl-py
diff --git a/testing/python/services.py b/testing/python/services.py
new file mode 100644
index 0000000..9a06d82
--- /dev/null
+++ b/testing/python/services.py
@@ -0,0 +1,261 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Testing service API implementations in Python."""
+
+from __future__ import absolute_import
+from __future__ import division
+# Placeholder for import for type annotations
+from __future__ import print_function
+
+import io
+
+import grpc
+import tink
+from tink import aead
+from tink import cleartext_keyset_handle
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature
+from tink.proto import tink_pb2
+from proto.testing import testing_api_pb2
+from proto.testing import testing_api_pb2_grpc
+
+
+class MetadataServicer(testing_api_pb2_grpc.MetadataServicer):
+ """A service with metadata about the server."""
+
+ def GetServerInfo(
+ self, request: testing_api_pb2.ServerInfoRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.ServerInfoResponse:
+ """Generates a keyset."""
+ return testing_api_pb2.ServerInfoResponse(language='python')
+
+
+class KeysetServicer(testing_api_pb2_grpc.KeysetServicer):
+ """A service for testing Keyset operations."""
+
+ def Generate(
+ self, request: testing_api_pb2.KeysetGenerateRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.KeysetGenerateResponse:
+ """Generates a keyset."""
+ try:
+ template = tink_pb2.KeyTemplate()
+ template.ParseFromString(request.template)
+ keyset_handle = tink.new_keyset_handle(template)
+ keyset = io.BytesIO()
+ cleartext_keyset_handle.write(
+ tink.BinaryKeysetWriter(keyset), keyset_handle)
+ return testing_api_pb2.KeysetGenerateResponse(keyset=keyset.getvalue())
+ except tink.TinkError as e:
+ return testing_api_pb2.KeysetGenerateResponse(err=str(e))
+
+ def Public(
+ self, request: testing_api_pb2.KeysetPublicRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.KeysetPublicResponse:
+ """Generates a public-key keyset from a private-key keyset."""
+ try:
+ private_keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.private_keyset))
+ public_keyset_handle = private_keyset_handle.public_keyset_handle()
+ public_keyset = io.BytesIO()
+ cleartext_keyset_handle.write(
+ tink.BinaryKeysetWriter(public_keyset), public_keyset_handle)
+ return testing_api_pb2.KeysetPublicResponse(
+ public_keyset=public_keyset.getvalue())
+ except tink.TinkError as e:
+ return testing_api_pb2.KeysetPublicResponse(err=str(e))
+
+ def ToJson(
+ self, request: testing_api_pb2.KeysetToJsonRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.KeysetToJsonResponse:
+ """Converts a keyset from binary to JSON format."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ json_keyset = io.StringIO()
+ cleartext_keyset_handle.write(
+ tink.JsonKeysetWriter(json_keyset), keyset_handle)
+ return testing_api_pb2.KeysetToJsonResponse(
+ json_keyset=json_keyset.getvalue())
+ except tink.TinkError as e:
+ return testing_api_pb2.KeysetToJsonResponse(err=str(e))
+
+ def FromJson(
+ self, request: testing_api_pb2.KeysetFromJsonRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.KeysetFromJsonResponse:
+ """Converts a keyset from JSON to binary format."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.JsonKeysetReader(request.json_keyset))
+ keyset = io.BytesIO()
+ cleartext_keyset_handle.write(
+ tink.BinaryKeysetWriter(keyset), keyset_handle)
+ return testing_api_pb2.KeysetFromJsonResponse(keyset=keyset.getvalue())
+ except tink.TinkError as e:
+ return testing_api_pb2.KeysetFromJsonResponse(err=str(e))
+
+
+class AeadServicer(testing_api_pb2_grpc.AeadServicer):
+ """A service for testing AEAD encryption."""
+
+ def Encrypt(
+ self, request: testing_api_pb2.AeadEncryptRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.AeadEncryptResponse:
+ """Encrypts a message."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(aead.Aead)
+ ciphertext = p.encrypt(request.plaintext, request.associated_data)
+ return testing_api_pb2.AeadEncryptResponse(ciphertext=ciphertext)
+ except tink.TinkError as e:
+ return testing_api_pb2.AeadEncryptResponse(err=str(e))
+
+ def Decrypt(
+ self, request: testing_api_pb2.AeadDecryptRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.AeadDecryptResponse:
+ """Decrypts a message."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(aead.Aead)
+ plaintext = p.decrypt(request.ciphertext, request.associated_data)
+ return testing_api_pb2.AeadDecryptResponse(plaintext=plaintext)
+ except tink.TinkError as e:
+ return testing_api_pb2.AeadDecryptResponse(err=str(e))
+
+
+class DeterministicAeadServicer(testing_api_pb2_grpc.DeterministicAeadServicer):
+ """A service for testing Deterministic AEAD encryption."""
+
+ def EncryptDeterministically(
+ self, request: testing_api_pb2.DeterministicAeadEncryptRequest,
+ context: grpc.ServicerContext
+ ) -> testing_api_pb2.DeterministicAeadEncryptResponse:
+ """Encrypts a message."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(daead.DeterministicAead)
+ ciphertext = p.encrypt_deterministically(request.plaintext,
+ request.associated_data)
+ return testing_api_pb2.DeterministicAeadEncryptResponse(
+ ciphertext=ciphertext)
+ except tink.TinkError as e:
+ return testing_api_pb2.DeterministicAeadEncryptResponse(err=str(e))
+
+ def DecryptDeterministically(
+ self, request: testing_api_pb2.DeterministicAeadDecryptRequest,
+ context: grpc.ServicerContext
+ ) -> testing_api_pb2.DeterministicAeadDecryptResponse:
+ """Decrypts a message."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(daead.DeterministicAead)
+ plaintext = p.decrypt_deterministically(request.ciphertext,
+ request.associated_data)
+ return testing_api_pb2.DeterministicAeadDecryptResponse(
+ plaintext=plaintext)
+ except tink.TinkError as e:
+ return testing_api_pb2.DeterministicAeadDecryptResponse(err=str(e))
+
+
+class MacServicer(testing_api_pb2_grpc.MacServicer):
+ """A service for testing MACs."""
+
+ def ComputeMac(
+ self, request: testing_api_pb2.ComputeMacRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.ComputeMacResponse:
+ """Computes a MAC."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(mac.Mac)
+ mac_value = p.compute_mac(request.data)
+ return testing_api_pb2.ComputeMacResponse(mac_value=mac_value)
+ except tink.TinkError as e:
+ return testing_api_pb2.ComputeMacResponse(err=str(e))
+
+ def VerifyMac(
+ self, request: testing_api_pb2.VerifyMacRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.VerifyMacResponse:
+ """Verifies a MAC value."""
+ try:
+ keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.keyset))
+ p = keyset_handle.primitive(mac.Mac)
+ p.verify_mac(request.mac_value, request.data)
+ return testing_api_pb2.VerifyMacResponse()
+ except tink.TinkError as e:
+ return testing_api_pb2.VerifyMacResponse(err=str(e))
+
+
+class HybridServicer(testing_api_pb2_grpc.HybridServicer):
+ """A service for testing hybrid encryption and decryption."""
+
+ def Encrypt(
+ self, request: testing_api_pb2.HybridEncryptRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.HybridEncryptResponse:
+ """Encrypts a message."""
+ try:
+ public_keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.public_keyset))
+ p = public_keyset_handle.primitive(hybrid.HybridEncrypt)
+ ciphertext = p.encrypt(request.plaintext, request.context_info)
+ return testing_api_pb2.HybridEncryptResponse(ciphertext=ciphertext)
+ except tink.TinkError as e:
+ return testing_api_pb2.HybridEncryptResponse(err=str(e))
+
+ def Decrypt(
+ self, request: testing_api_pb2.HybridDecryptRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.HybridDecryptResponse:
+ """Decrypts a message."""
+ try:
+ private_keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.private_keyset))
+ p = private_keyset_handle.primitive(hybrid.HybridDecrypt)
+ plaintext = p.decrypt(request.ciphertext, request.context_info)
+ return testing_api_pb2.HybridDecryptResponse(plaintext=plaintext)
+ except tink.TinkError as e:
+ return testing_api_pb2.HybridDecryptResponse(err=str(e))
+
+
+class SignatureServicer(testing_api_pb2_grpc.SignatureServicer):
+ """A service for testing signatures."""
+
+ def Sign(
+ self, request: testing_api_pb2.SignatureSignRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.SignatureSignResponse:
+ """Signs a message."""
+ try:
+ private_keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.private_keyset))
+ p = private_keyset_handle.primitive(signature.PublicKeySign)
+ signature_value = p.sign(request.data)
+ return testing_api_pb2.SignatureSignResponse(signature=signature_value)
+ except tink.TinkError as e:
+ return testing_api_pb2.SignatureSignResponse(err=str(e))
+
+ def Verify(
+ self, request: testing_api_pb2.SignatureVerifyRequest,
+ context: grpc.ServicerContext) -> testing_api_pb2.SignatureVerifyResponse:
+ """Verifies a signature."""
+ try:
+ public_keyset_handle = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(request.public_keyset))
+ p = public_keyset_handle.primitive(signature.PublicKeyVerify)
+ p.verify(request.signature, request.data)
+ return testing_api_pb2.SignatureVerifyResponse()
+ except tink.TinkError as e:
+ return testing_api_pb2.SignatureVerifyResponse(err=str(e))
diff --git a/testing/python/services_test.py b/testing/python/services_test.py
new file mode 100644
index 0000000..7ce6995
--- /dev/null
+++ b/testing/python/services_test.py
@@ -0,0 +1,402 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests for tink.tools.testing.python.testing_server."""
+
+from absl import logging
+from absl.testing import absltest
+import grpc
+
+import tink
+from tink import aead
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature
+
+
+from proto.testing import testing_api_pb2
+import services
+
+
+class DummyServicerContext(grpc.ServicerContext):
+
+ def is_active(self):
+ pass
+
+ def time_remaining(self):
+ pass
+
+ def cancel(self):
+ pass
+
+ def add_callback(self, callback):
+ pass
+
+ def invocation_metadata(self):
+ pass
+
+ def peer(self):
+ pass
+
+ def peer_identities(self):
+ pass
+
+ def peer_identity_key(self):
+ pass
+
+ def auth_context(self):
+ pass
+
+ def set_compression(self, compression):
+ pass
+
+ def send_initial_metadata(self, initial_metadata):
+ pass
+
+ def set_trailing_metadata(self, trailing_metadata):
+ pass
+
+ def abort(self, code, details):
+ pass
+
+ def abort_with_status(self, status):
+ pass
+
+ def set_code(self, code):
+ pass
+
+ def set_details(self, details):
+ pass
+
+ def disable_next_message_compression(self):
+ pass
+
+
+class ServicesTest(absltest.TestCase):
+
+ _ctx = DummyServicerContext()
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ aead.register()
+ daead.register()
+ mac.register()
+ hybrid.register()
+ signature.register()
+
+ def test_from_json(self):
+ keyset_servicer = services.KeysetServicer()
+ json_keyset = """
+ {
+ "primaryKeyId": 42,
+ "key": [
+ {
+ "keyData": {
+ "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
+ "keyMaterialType": "SYMMETRIC",
+ "value": "AFakeTestKeyValue1234567"
+
+ },
+ "outputPrefixType": "TINK",
+ "keyId": 42,
+ "status": "ENABLED"
+ }
+ ]
+ }"""
+ request = testing_api_pb2.KeysetFromJsonRequest(json_keyset=json_keyset)
+ response = keyset_servicer.FromJson(request, self._ctx)
+ self.assertEqual(response.WhichOneof('result'), 'keyset')
+ keyset = tink.BinaryKeysetReader(response.keyset).read()
+ self.assertEqual(keyset.primary_key_id, 42)
+ self.assertLen(keyset.key, 1)
+
+ def test_from_json_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ request = testing_api_pb2.KeysetFromJsonRequest(json_keyset='bad json')
+ response = keyset_servicer.FromJson(request, self._ctx)
+ self.assertEqual(response.WhichOneof('result'), 'err')
+ self.assertNotEmpty(response.err)
+
+ def test_generate_to_from_json(self):
+ keyset_servicer = services.KeysetServicer()
+
+ template = aead.aead_key_templates.AES128_GCM.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+
+ tojson_request = testing_api_pb2.KeysetToJsonRequest(keyset=keyset)
+ tojson_response = keyset_servicer.ToJson(tojson_request, self._ctx)
+ self.assertEqual(tojson_response.WhichOneof('result'), 'json_keyset')
+ json_keyset = tojson_response.json_keyset
+
+ fromjson_request = testing_api_pb2.KeysetFromJsonRequest(
+ json_keyset=json_keyset)
+ fromjson_response = keyset_servicer.FromJson(fromjson_request, self._ctx)
+ self.assertEqual(fromjson_response.WhichOneof('result'), 'keyset')
+ self.assertEqual(fromjson_response.keyset, keyset)
+
+ def test_to_json_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ request = testing_api_pb2.KeysetToJsonRequest(keyset=b'bad keyset')
+ response = keyset_servicer.ToJson(request, self._ctx)
+ self.assertEqual(response.WhichOneof('result'), 'err')
+ self.assertNotEmpty(response.err)
+
+ def test_generate_encrypt_decrypt(self):
+ keyset_servicer = services.KeysetServicer()
+ aead_servicer = services.AeadServicer()
+
+ template = aead.aead_key_templates.AES128_GCM.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ associated_data = b'associated_data'
+ enc_request = testing_api_pb2.AeadEncryptRequest(
+ keyset=keyset, plaintext=plaintext, associated_data=associated_data)
+ enc_response = aead_servicer.Encrypt(enc_request, self._ctx)
+ self.assertEqual(enc_response.WhichOneof('result'), 'ciphertext')
+ ciphertext = enc_response.ciphertext
+ dec_request = testing_api_pb2.AeadDecryptRequest(
+ keyset=keyset, ciphertext=ciphertext, associated_data=associated_data)
+ dec_response = aead_servicer.Decrypt(dec_request, self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'plaintext')
+ self.assertEqual(dec_response.plaintext, plaintext)
+
+ def test_generate_decrypt_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ aead_servicer = services.AeadServicer()
+
+ template = aead.aead_key_templates.AES128_GCM.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+
+ ciphertext = b'some invalid ciphertext'
+ associated_data = b'associated_data'
+ dec_request = testing_api_pb2.AeadDecryptRequest(
+ keyset=keyset, ciphertext=ciphertext, associated_data=associated_data)
+ dec_response = aead_servicer.Decrypt(dec_request, self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'err')
+ logging.info('Error in response: %s', dec_response.err)
+ self.assertNotEmpty(dec_response.err)
+
+ def test_server_info(self):
+ metadata_servicer = services.MetadataServicer()
+ request = testing_api_pb2.ServerInfoRequest()
+ response = metadata_servicer.GetServerInfo(request, self._ctx)
+ self.assertEqual(response.language, 'python')
+
+ def test_generate_encrypt_decrypt_deterministically(self):
+ keyset_servicer = services.KeysetServicer()
+ daead_servicer = services.DeterministicAeadServicer()
+
+ template_proto = daead.deterministic_aead_key_templates.AES256_SIV
+ template = template_proto.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ associated_data = b'associated_data'
+ enc_request = testing_api_pb2.DeterministicAeadEncryptRequest(
+ keyset=keyset, plaintext=plaintext, associated_data=associated_data)
+ enc_response = daead_servicer.EncryptDeterministically(enc_request,
+ self._ctx)
+ self.assertEqual(enc_response.WhichOneof('result'), 'ciphertext')
+ enc_response2 = daead_servicer.EncryptDeterministically(enc_request,
+ self._ctx)
+ self.assertEqual(enc_response2.WhichOneof('result'), 'ciphertext')
+ self.assertEqual(enc_response2.ciphertext, enc_response.ciphertext)
+ ciphertext = enc_response.ciphertext
+ dec_request = testing_api_pb2.DeterministicAeadDecryptRequest(
+ keyset=keyset, ciphertext=ciphertext, associated_data=associated_data)
+ dec_response = daead_servicer.DecryptDeterministically(dec_request,
+ self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'plaintext')
+ self.assertEqual(dec_response.plaintext, plaintext)
+
+ def test_generate_decrypt_deterministically_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ daead_servicer = services.DeterministicAeadServicer()
+
+ template_proto = daead.deterministic_aead_key_templates.AES256_SIV
+ template = template_proto.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+
+ ciphertext = b'some invalid ciphertext'
+ associated_data = b'associated_data'
+ dec_request = testing_api_pb2.DeterministicAeadDecryptRequest(
+ keyset=keyset, ciphertext=ciphertext, associated_data=associated_data)
+ dec_response = daead_servicer.DecryptDeterministically(dec_request,
+ self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'err')
+ logging.info('Error in response: %s', dec_response.err)
+ self.assertNotEmpty(dec_response.err)
+
+ def test_generate_compute_verify_mac(self):
+ keyset_servicer = services.KeysetServicer()
+ mac_servicer = services.MacServicer()
+
+ template = mac.mac_key_templates.HMAC_SHA256_128BITTAG.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+ data = b'The quick brown fox jumps over the lazy dog'
+ comp_request = testing_api_pb2.ComputeMacRequest(keyset=keyset, data=data)
+ comp_response = mac_servicer.ComputeMac(comp_request, self._ctx)
+ self.assertEqual(comp_response.WhichOneof('result'), 'mac_value')
+ mac_value = comp_response.mac_value
+ verify_request = testing_api_pb2.VerifyMacRequest(
+ keyset=keyset, mac_value=mac_value, data=data)
+ verify_response = mac_servicer.VerifyMac(verify_request, self._ctx)
+ self.assertEmpty(verify_response.err)
+
+ def test_generate_compute_verify_mac_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ mac_servicer = services.MacServicer()
+
+ template = mac.mac_key_templates.HMAC_SHA256_128BITTAG.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ keyset = gen_response.keyset
+
+ verify_request = testing_api_pb2.VerifyMacRequest(
+ keyset=keyset, mac_value=b'invalid mac_value', data=b'data')
+ verify_response = mac_servicer.VerifyMac(verify_request, self._ctx)
+ logging.info('Error in response: %s', verify_response.err)
+ self.assertNotEmpty(verify_response.err)
+
+ def test_generate_hybrid_encrypt_decrypt(self):
+ keyset_servicer = services.KeysetServicer()
+ hybrid_servicer = services.HybridServicer()
+
+ tp = hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM
+ template = tp.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEmpty(gen_response.err)
+ private_keyset = gen_response.keyset
+
+ pub_request = testing_api_pb2.KeysetPublicRequest(
+ private_keyset=private_keyset)
+ pub_response = keyset_servicer.Public(pub_request, self._ctx)
+ self.assertEqual(pub_response.WhichOneof('result'), 'public_keyset')
+ public_keyset = pub_response.public_keyset
+
+ plaintext = b'The quick brown fox jumps over the lazy dog'
+ context_info = b'context_info'
+ enc_request = testing_api_pb2.HybridEncryptRequest(
+ public_keyset=public_keyset,
+ plaintext=plaintext,
+ context_info=context_info)
+ enc_response = hybrid_servicer.Encrypt(enc_request, self._ctx)
+ self.assertEqual(enc_response.WhichOneof('result'), 'ciphertext')
+ ciphertext = enc_response.ciphertext
+
+ dec_request = testing_api_pb2.HybridDecryptRequest(
+ private_keyset=private_keyset,
+ ciphertext=ciphertext,
+ context_info=context_info)
+ dec_response = hybrid_servicer.Decrypt(dec_request, self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'plaintext')
+ self.assertEqual(dec_response.plaintext, plaintext)
+
+ def test_generate_hybrid_encrypt_decrypt_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ hybrid_servicer = services.HybridServicer()
+
+ tp = hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM
+ template = tp.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ private_keyset = gen_response.keyset
+
+ dec_request = testing_api_pb2.HybridDecryptRequest(
+ private_keyset=private_keyset,
+ ciphertext=b'invalid ciphertext',
+ context_info=b'context_info')
+ dec_response = hybrid_servicer.Decrypt(dec_request, self._ctx)
+ self.assertEqual(dec_response.WhichOneof('result'), 'err')
+ self.assertNotEmpty(dec_response.err)
+
+ def test_sign_verify(self):
+ keyset_servicer = services.KeysetServicer()
+ signature_servicer = services.SignatureServicer()
+
+ template = signature.signature_key_templates.ECDSA_P256.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ private_keyset = gen_response.keyset
+
+ pub_request = testing_api_pb2.KeysetPublicRequest(
+ private_keyset=private_keyset)
+ pub_response = keyset_servicer.Public(pub_request, self._ctx)
+ self.assertEqual(pub_response.WhichOneof('result'), 'public_keyset')
+ public_keyset = pub_response.public_keyset
+
+ data = b'The quick brown fox jumps over the lazy dog'
+
+ sign_request = testing_api_pb2.SignatureSignRequest(
+ private_keyset=private_keyset,
+ data=data)
+ sign_response = signature_servicer.Sign(sign_request, self._ctx)
+ self.assertEqual(sign_response.WhichOneof('result'), 'signature')
+ a_signature = sign_response.signature
+
+ verify_request = testing_api_pb2.SignatureVerifyRequest(
+ public_keyset=public_keyset,
+ signature=a_signature,
+ data=data)
+ verify_response = signature_servicer.Verify(verify_request, self._ctx)
+ self.assertEmpty(verify_response.err)
+
+ def test_sign_verify_fail(self):
+ keyset_servicer = services.KeysetServicer()
+ signature_servicer = services.SignatureServicer()
+
+ template = signature.signature_key_templates.ECDSA_P256.SerializeToString()
+ gen_request = testing_api_pb2.KeysetGenerateRequest(template=template)
+ gen_response = keyset_servicer.Generate(gen_request, self._ctx)
+ self.assertEqual(gen_response.WhichOneof('result'), 'keyset')
+ self.assertEmpty(gen_response.err)
+ private_keyset = gen_response.keyset
+
+ pub_request = testing_api_pb2.KeysetPublicRequest(
+ private_keyset=private_keyset)
+ pub_response = keyset_servicer.Public(pub_request, self._ctx)
+ self.assertEqual(pub_response.WhichOneof('result'), 'public_keyset')
+ public_keyset = pub_response.public_keyset
+
+ invalid_request = testing_api_pb2.SignatureVerifyRequest(
+ public_keyset=public_keyset,
+ signature=b'invalid signature',
+ data=b'The quick brown fox jumps over the lazy dog')
+ invalid_response = signature_servicer.Verify(invalid_request, self._ctx)
+ self.assertNotEmpty(invalid_response.err)
+
+
+if __name__ == '__main__':
+ absltest.main()
diff --git a/testing/python/testing_server.py b/testing/python/testing_server.py
new file mode 100644
index 0000000..e5bfd3e
--- /dev/null
+++ b/testing/python/testing_server.py
@@ -0,0 +1,67 @@
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tink Primitive Testing Service in Python."""
+
+from __future__ import absolute_import
+from __future__ import division
+# Placeholder for import for type annotations
+from __future__ import print_function
+
+from concurrent import futures
+
+from absl import app
+from absl import flags
+import grpc
+from tink import aead
+from tink import daead
+from tink import hybrid
+from tink import mac
+from tink import signature
+
+from proto.testing import testing_api_pb2_grpc
+
+import services
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_integer('port', 10000, 'The port of the server.')
+
+
+def main(unused_argv):
+ aead.register()
+ daead.register()
+ hybrid.register()
+ mac.register()
+ signature.register()
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=2))
+ testing_api_pb2_grpc.add_MetadataServicer_to_server(
+ services.MetadataServicer(), server)
+ testing_api_pb2_grpc.add_KeysetServicer_to_server(
+ services.KeysetServicer(), server)
+ testing_api_pb2_grpc.add_AeadServicer_to_server(
+ services.AeadServicer(), server)
+ testing_api_pb2_grpc.add_DeterministicAeadServicer_to_server(
+ services.DeterministicAeadServicer(), server)
+ testing_api_pb2_grpc.add_MacServicer_to_server(
+ services.MacServicer(), server)
+ testing_api_pb2_grpc.add_HybridServicer_to_server(
+ services.HybridServicer(), server)
+ testing_api_pb2_grpc.add_SignatureServicer_to_server(
+ services.SignatureServicer(), server)
+ server.add_secure_port('[::]:%d' % FLAGS.port,
+ grpc.local_server_credentials())
+ server.start()
+ server.wait_for_termination()
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/third_party/rules_protobuf/BUILD.bazel b/third_party/rules_protobuf/BUILD.bazel
deleted file mode 100644
index 001dcb9..0000000
--- a/third_party/rules_protobuf/BUILD.bazel
+++ /dev/null
@@ -1,5 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-licenses(["notice"])
-
-exports_files(["LICENSE"])
diff --git a/third_party/rules_protobuf/LICENSE b/third_party/rules_protobuf/LICENSE
deleted file mode 100644
index d68d510..0000000
--- a/third_party/rules_protobuf/LICENSE
+++ /dev/null
@@ -1,204 +0,0 @@
-Copyright 2016 PubRef.org
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/third_party/rules_protobuf/README.md b/third_party/rules_protobuf/README.md
deleted file mode 100644
index 1767faa..0000000
--- a/third_party/rules_protobuf/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Bazel Skylark rules for building protobufs for ObjC
-
-This is a minimal fork of [Rules Protobuf](https://github.com/pubref/rules_protobuf)
-that supports building protobuf for ObjC.
-
-Tink needs temporarily depend on these rules because objc_proto_library is
-not working properly. See https://github.com/bazelbuild/bazel/issues/1802.
-
-Once either Bazel or Protobuf team fixes objc_proto_library, these rules
-can be removed.
diff --git a/third_party/rules_protobuf/objc/BUILD.bazel b/third_party/rules_protobuf/objc/BUILD.bazel
deleted file mode 100644
index dbee277..0000000
--- a/third_party/rules_protobuf/objc/BUILD.bazel
+++ /dev/null
@@ -1,14 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-licenses(["notice"])
-
-load("//third_party/rules_protobuf/protobuf:rules.bzl", "proto_language")
-
-proto_language(
- name = "objc",
- output_file_style = "pascal",
- pb_file_extensions = [
- ".pbobjc.h",
- ".pbobjc.m",
- ],
-)
diff --git a/third_party/rules_protobuf/objc/rules.bzl b/third_party/rules_protobuf/objc/rules.bzl
deleted file mode 100644
index 69edbe1..0000000
--- a/third_party/rules_protobuf/objc/rules.bzl
+++ /dev/null
@@ -1,10 +0,0 @@
-"""Compiles protobuf for ObjC.
-
-"""
-
-load("//third_party/rules_protobuf/protobuf:rules.bzl", "proto_compile")
-
-def objc_proto_compile(
- langs = [str(Label("//third_party/rules_protobuf/objc"))],
- **kwargs):
- proto_compile(langs = langs, **kwargs)
diff --git a/third_party/rules_protobuf/protobuf/BUILD.bazel b/third_party/rules_protobuf/protobuf/BUILD.bazel
deleted file mode 100644
index e6d05e7..0000000
--- a/third_party/rules_protobuf/protobuf/BUILD.bazel
+++ /dev/null
@@ -1,3 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-licenses(["notice"])
diff --git a/third_party/rules_protobuf/protobuf/internal/proto_compile.bzl b/third_party/rules_protobuf/protobuf/internal/proto_compile.bzl
deleted file mode 100644
index c0bd552..0000000
--- a/third_party/rules_protobuf/protobuf/internal/proto_compile.bzl
+++ /dev/null
@@ -1,522 +0,0 @@
-"""Compiles protobuf.
-
-"""
-
-def _capitalize(s):
- return s[0:1].upper() + s[1:]
-
-def _pascal_case(s):
- return "".join([_capitalize(part) for part in s.split("_")])
-
-def _emit_params_file_action(ctx, path, mnemonic, cmds):
- """Helper function that writes a potentially long command list to a file.
- Args:
- ctx (struct): The ctx object.
- path (string): the file path where the params file should be written.
- mnemonic (string): the action mnemomic.
- cmds (list<string>): the command list.
- Returns:
- (File): an executable file that runs the command set.
- """
- filename = "%s.%sFile.params" % (path, mnemonic)
- f = ctx.new_file(ctx.configuration.bin_dir, filename)
- ctx.actions.write(
- output = f,
- content = "\n".join(["set -e"] + cmds),
- is_executable = True,
- )
- return f
-
-def _get_relative_dirname(base, file):
- """Return a dirname in the form of path segments relative to base.
- If the file.short_path is not within base, return empty list.
- Example: if base="foo/bar/baz.txt"
- and file.short_path="bar/baz.txt",
- return ["bar"].
- Args:
- base (string): the base dirname (ctx.label.package)
- file (File): the file to calculate relative dirname.
- Returns:
- (list<string>): path
- """
- path = file.dirname
- if not path.startswith(base):
- return []
- parts = path.split("/")
- if parts[0] == "external":
- # ignore off the first two items since we'll be cd'ing into
- # this dir.
- return parts[2:]
- base_parts = base.split("/")
- return parts[len(base_parts):]
-
-def _get_offset_path(root, path):
- """Adjust path relative to offset"""
-
- if path.startswith("/"):
- fail("path argument must not be absolute: %s" % path)
-
- if not root:
- return path
-
- if root == ".":
- return path
-
- # "external/foobar/file.proto" --> "file.proto"
- if path.startswith(root):
- start = len(root)
- if not root.endswith("/"):
- start += 1
- return path[start:]
-
- depth = root.count("/") + 1
- return "../" * depth + path
-
-def _get_import_mappings_for(files, prefix, label):
- """For a set of files that belong to the given context label, create a mapping to the given prefix."""
-
- mappings = {}
- for file in files:
- src = file.short_path
-
- # File in an external repo looks like:
- # '../WORKSPACE/SHORT_PATH'. We want just the SHORT_PATH.
- if src.startswith("../"):
- parts = src.split("/")
- src = "/".join(parts[2:])
- dst = [prefix, label.package]
- name_parts = label.name.split(".")
-
- # special case to elide last part if the name is
- # 'go_default_library.pb'
- if name_parts[0] != "go_default_library":
- dst.append(name_parts[0])
- mappings[src] = "/".join(dst)
-
- return mappings
-
-def _build_output_jar(run, builder):
- """Build a jar file for protoc to dump java classes into."""
- ctx = run.ctx
- execdir = run.data.execdir
- name = run.lang.name
- protojar = ctx.actions.declare_file("%s_%s.jar" % (run.data.label.name, name))
- builder["outputs"] += [protojar]
- builder[name + "_jar"] = protojar
- builder[name + "_outdir"] = _get_offset_path(execdir, protojar.path)
-
-def _build_output_library(run, builder):
- """Build a library.js file for protoc to dump java classes into."""
- ctx = run.ctx
- execdir = run.data.execdir
- name = run.lang.name
- jslib = ctx.actions.declare_file(run.data.label.name + run.lang.pb_file_extensions[0])
- builder["jslib"] = [jslib]
- builder["outputs"] += [jslib]
-
- parts = jslib.short_path.rpartition("/")
- filename = "/".join([parts[0], run.data.label.name])
- library_path = _get_offset_path(run.data.execdir, filename)
- builder[name + "_pb_options"] += ["library=" + library_path]
-
-def _build_output_srcjar(run, builder):
- ctx = run.ctx
- name = run.lang.name
- protojar = builder[name + "_jar"]
- srcjar_name = "%s_%s.srcjar" % (run.data.label.name, name)
- srcjar = ctx.actions.declare_file("%s_%s.srcjar" % (run.data.label.name, name))
- run.ctx.action(
- mnemonic = "CpJarToSrcJar",
- inputs = [protojar],
- outputs = [srcjar],
- arguments = [protojar.path, srcjar.path],
- command = "cp $1 $2",
- )
-
- # Remove protojar from the list of provided outputs
- builder["outputs"] = [e for e in builder["outputs"] if e != protojar]
- builder["outputs"] += [srcjar]
-
- if run.data.verbose > 2:
- print("Copied jar %s srcjar to %s" % (protojar.path, srcjar.path))
-
-def _build_output_files(run, builder):
- """Build a list of files we expect to be generated."""
-
- ctx = run.ctx
- protos = run.data.protos
- if not protos:
- fail("Empty proto input list.", "protos")
-
- exts = run.exts
-
- for file in protos:
- base = file.basename[:-len(".proto")]
- if run.lang.output_file_style == "pascal":
- base = _pascal_case(base)
- if run.lang.output_file_style == "capitalize":
- base = _capitalize(base)
- for ext in exts:
- path = _get_relative_dirname(ctx.label.package, file)
- path.append(base + ext)
- pbfile = ctx.actions.declare_file("/".join(path))
- builder["outputs"] += [pbfile]
-
-def _build_output_libdir(run, builder):
- # This is currently csharp-specific, which needs to have the
- # output_dir positively adjusted to the package directory.
- ctx = run.ctx
- execdir = run.data.execdir
- name = run.lang.name
- builder[name + "_outdir"] = _get_offset_path(execdir, run.data.descriptor_set.dirname)
- _build_output_files(run, builder)
-
-def _build_descriptor_set(data, builder):
- """Build a list of files we expect to be generated."""
- builder["args"] += ["--descriptor_set_out=" + _get_offset_path(data.execdir, data.descriptor_set.path)]
-
-def _build_plugin_invocation(name, plugin, execdir, builder):
- """Add a '--plugin=NAME=PATH' argument if the language descriptor
- requires one.
- """
- tool = _get_offset_path(execdir, plugin.path)
- builder["inputs"] += [plugin]
- builder["args"] += ["--plugin=protoc-gen-%s=%s" % (name, tool)]
-
-def _build_protobuf_invocation(run, builder):
- """Build a --plugin option if required for basic protobuf generation.
- Args:
- run (struct): the compilation run object.
- builder (dict): the compilation builder data.
- Built-in language don't need this.
- """
- lang = run.lang
- if not lang.pb_plugin:
- return
- name = lang.pb_plugin_name or lang.name
- _build_plugin_invocation(
- name,
- lang.pb_plugin,
- run.data.execdir,
- builder,
- )
-
-def _get_mappings(files, label, prefix):
- """For a set of files that belong the the given context label, create a mapping to the given prefix."""
- mappings = {}
- for file in files:
- src = file.short_path
-
- #print("mapping file short path: %s" % src)
- # File in an external repo looks like:
- # '../WORKSPACE/SHORT_PATH'. We want just the SHORT_PATH.
- if src.startswith("../"):
- parts = src.split("/")
- src = "/".join(parts[2:])
- dst = [prefix]
- if label.package:
- dst.append(label.package)
- name_parts = label.name.split(".")
-
- # special case to elide last part if the name is
- # 'go_default_library.pb'
- if name_parts[0] != "go_default_library":
- dst.append(name_parts[0])
- mappings[src] = "/".join(dst)
- return mappings
-
-def _build_base_namespace(run, builder):
- pass
-
-def _build_importmappings(run, builder):
- """Override behavior to add plugin options before building the --go_out option"""
- ctx = run.ctx
- go_prefix = run.data.prefix or run.lang.prefix
- opts = []
-
- # Build the list of import mappings. Start with any configured on
- # the rule by attributes.
- mappings = run.lang.importmap + run.data.importmap
- mappings += _get_mappings(run.data.protos, run.data.label, go_prefix)
-
- # Then add in the transitive set from dependent rules.
- for unit in run.data.transitive_units:
- mappings += unit.transitive_mappings
-
- if run.data.verbose > 1:
- print("go_importmap: %s" % mappings)
-
- for k, v in mappings.items():
- opts += ["M%s=%s" % (k, v)]
-
- builder["transitive_mappings"] = mappings
-
-def _build_plugin_out(name, outdir, options, builder):
- """Build the --{lang}_out argument for a given plugin."""
- arg = outdir
- if options:
- arg = ",".join(options) + ":" + arg
- builder["args"] += ["--%s_out=%s" % (name, arg)]
-
-def _build_protobuf_out(run, builder):
- """Build the --{lang}_out option"""
- lang = run.lang
- name = lang.pb_plugin_name or lang.name
- outdir = builder.get(lang.name + "_outdir", run.outdir)
- options = builder.get(lang.name + "_pb_options", [])
-
- _build_plugin_out(name, outdir, options, builder)
-
-def _get_outdir(ctx, lang, execdir):
- if ctx.attr.output_to_workspace:
- outdir = "."
- else:
- outdir = ctx.var["GENDIR"]
- path = _get_offset_path(execdir, outdir)
- if execdir != ".":
- path += "/" + execdir
- return path
-
-def _get_external_root(ctx):
- # Compte set of "external workspace roots" that the proto
- # sourcefiles belong to.
- external_roots = []
- for file in ctx.files.protos:
- path = file.path.split("/")
- if path[0] == "external":
- external_roots += ["/".join(path[0:2])]
-
- # This set size must be 0 or 1. (all source files must exist in this
- # workspace or the same external workspace).
- roots = depset(external_roots)
- n = len(roots.to_list())
- if n:
- if n > 1:
- fail(
- """
- You are attempting simultaneous compilation of protobuf source files that span multiple workspaces (%s).
- Decompose your library rules into smaller units having filesets that belong to only a single workspace at a time.
- Note that it is OK to *import* across multiple workspaces, but not compile them as file inputs to protoc.
- """ % roots,
- )
- else:
- return external_roots[0]
- else:
- return "."
-
-def _compile(ctx, unit):
- execdir = unit.data.execdir
-
- protoc = _get_offset_path(execdir, unit.compiler.path)
- imports = ["--proto_path=" + i for i in unit.imports.to_list()]
- srcs = [_get_offset_path(execdir, p.path) for p in unit.data.protos]
- protoc_cmd = [protoc] + unit.args.to_list() + imports + srcs
- manifest = [f.short_path for f in unit.outputs.to_list()]
-
- transitive_units = depset(transitive = [u.inputs for u in unit.data.transitive_units])
- inputs = depset(transitive = [unit.inputs, transitive_units]).to_list()
- outputs = unit.outputs.to_list()
-
- cmds = [" ".join(protoc_cmd)]
- if execdir != ".":
- cmds.insert(0, "cd %s" % execdir)
-
- if unit.data.output_to_workspace:
- print(
- """
->**************************************************************************
-* - Generating files into the workspace... This is potentially *
-* dangerous (may overwrite existing files) and violates bazel's *
-* sandbox policy. *
-* - Disregard "ERROR: output 'foo.pb.*' was not created." messages. *
-* - Build will halt following the "not all outputs were created" message. *
-* - Output manifest is printed below. *
-**************************************************************************<
-%s
->*************************************************************************<
-""" % "\n".join(manifest),
- )
-
- if unit.data.verbose:
- print(
- """
-************************************************************
-cd $(bazel info execution_root)%s && \
-%s
-************************************************************
-%s
-************************************************************
-""" % (
- "" if execdir == "." else "/" + execdir,
- " \\ \n".join(protoc_cmd),
- "\n".join(manifest),
- ),
- )
-
- if unit.data.verbose > 2:
- for i in range(len(protoc_cmd)):
- print(" > cmd%s: %s" % (i, protoc_cmd[i]))
- for i in range(len(inputs)):
- print(" > input%s: %s" % (i, inputs[i]))
- for i in range(len(outputs)):
- print(" > output%s: %s" % (i, outputs[i]))
-
- ctx.actions.run_shell(
- mnemonic = "ProtoCompile",
- command = " && ".join(cmds),
- inputs = inputs,
- outputs = outputs,
- tools = [unit.compiler],
- )
-
-def _proto_compile_impl(ctx):
- if ctx.attr.verbose > 1:
- print("proto_compile %s:%s" % (ctx.build_file_path, ctx.label.name))
-
- # Calculate list of external roots and return the base directory
- # we'll use for the protoc invocation. Usually this is '.', but if
- # not, its 'external/WORKSPACE'
- execdir = _get_external_root(ctx)
-
- # Propogate proto deps compilation units.
- transitive_units = []
- for dep in ctx.attr.deps:
- for unit in dep.proto_compile_result.transitive_units:
- transitive_units.append(unit)
-
- if ctx.attr.prefix:
- prefix = ctx.attr.prefix.go_prefix
- else:
- prefix = ""
-
- # Immutable global state for this compiler run.
- data = struct(
- label = ctx.label,
- workspace_name = ctx.workspace_name,
- prefix = prefix,
- execdir = execdir,
- protos = ctx.files.protos,
- descriptor_set = ctx.outputs.descriptor_set,
- importmap = ctx.attr.importmap,
- pb_options = ctx.attr.pb_options,
- verbose = ctx.attr.verbose,
- transitive_units = transitive_units,
- output_to_workspace = ctx.attr.output_to_workspace,
- )
-
- #print("transitive_units: %s" % transitive_units)
-
- # Mutable global state to be populated by the classes.
- builder = {
- "args": [], # list of string
- "imports": ctx.attr.imports + ["."],
- "inputs": ctx.files.protos + ctx.files.inputs,
- "outputs": [],
- }
-
- # Build a list of structs that will be processed in this compiler
- # run.
- runs = []
- for l in ctx.attr.langs:
- lang = l.proto_language
-
- exts = []
- if lang.supports_pb:
- exts += lang.pb_file_extensions
-
- runs.append(struct(
- ctx = ctx,
- outdir = _get_outdir(ctx, lang, execdir),
- lang = lang,
- data = data,
- exts = exts,
- output_to_jar = lang.output_to_jar,
- ))
-
- builder["inputs"] += lang.pb_inputs
- builder["imports"] += lang.pb_imports
- builder[lang.name + "_pb_options"] = lang.pb_options + data.pb_options
-
- _build_descriptor_set(data, builder)
-
- for run in runs:
- if run.lang.output_to_jar:
- _build_output_jar(run, builder)
- elif run.lang.output_to_library:
- _build_output_library(run, builder)
- elif run.lang.output_to_libdir:
- _build_output_libdir(run, builder)
- else:
- _build_output_files(run, builder)
- if run.lang.prefix: # golang-specific
- _build_importmappings(run, builder)
- if run.lang.supports_pb:
- _build_protobuf_invocation(run, builder)
- _build_protobuf_out(run, builder)
-
- # Build final immutable compilation unit for rule and transitive beyond
- unit = struct(
- compiler = ctx.executable.protoc,
- data = data,
- transitive_mappings = builder.get("transitive_mappings", {}),
- args = depset(builder["args"] + ctx.attr.args),
- imports = depset(builder["imports"]),
- inputs = depset(builder["inputs"]),
- outputs = depset(builder["outputs"] + [ctx.outputs.descriptor_set]),
- )
-
- # Run protoc
- _compile(ctx, unit)
-
- for run in runs:
- if run.lang.output_to_jar:
- _build_output_srcjar(run, builder)
-
- files = depset(builder["outputs"])
-
- return struct(
- files = files,
- proto_compile_result = struct(
- unit = unit,
- transitive_units = transitive_units + [unit],
- ),
- )
-
-proto_compile = rule(
- implementation = _proto_compile_impl,
- attrs = {
- "args": attr.string_list(),
- "langs": attr.label_list(
- providers = ["proto_language"],
- allow_files = False,
- mandatory = False,
- ),
- "protos": attr.label_list(
- allow_files = [".proto"],
- ),
- "deps": attr.label_list(
- providers = ["proto_compile_result"],
- ),
- "protoc": attr.label(
- default = Label("@com_google_protobuf//:protoc"),
- cfg = "host",
- executable = True,
- ),
- "prefix": attr.label(
- providers = ["go_prefix"],
- ),
- "root": attr.string(),
- "imports": attr.string_list(),
- "importmap": attr.string_dict(),
- "inputs": attr.label_list(
- allow_files = True,
- ),
- "pb_options": attr.string_list(),
- "output_to_workspace": attr.bool(),
- "verbose": attr.int(),
- },
- outputs = {
- "descriptor_set": "%{name}.descriptor_set",
- },
- output_to_genfiles = True, # this needs to be set for cc-rules.
-)
diff --git a/third_party/rules_protobuf/protobuf/internal/proto_language.bzl b/third_party/rules_protobuf/protobuf/internal/proto_language.bzl
deleted file mode 100644
index cf69f7a..0000000
--- a/third_party/rules_protobuf/protobuf/internal/proto_language.bzl
+++ /dev/null
@@ -1,92 +0,0 @@
-"""Compiles protobuf.
-
-"""
-
-def _proto_language_impl(ctx):
- prefix = None
- if hasattr(ctx.attr.prefix, "go_prefix"):
- prefix = ctx.attr.prefix.go_prefix
- return struct(
- proto_language = struct(
- name = ctx.label.name,
- output_to_workspace = ctx.attr.output_to_workspace,
- output_to_jar = ctx.attr.output_to_jar,
- output_to_library = ctx.attr.output_to_library,
- output_to_libdir = ctx.attr.output_to_libdir,
- output_file_style = ctx.attr.output_file_style,
- supports_pb = ctx.attr.supports_pb,
- pb_file_extensions = ctx.attr.pb_file_extensions,
- pb_options = ctx.attr.pb_options,
- pb_imports = ctx.attr.pb_imports,
- pb_inputs = ctx.files.pb_inputs,
- pb_plugin_name = ctx.attr.pb_plugin_name,
- pb_plugin = ctx.executable.pb_plugin,
- pb_compile_deps = ctx.files.pb_compile_deps,
- pb_runtime_deps = ctx.files.pb_runtime_deps,
- prefix = prefix,
- importmap = ctx.attr.importmap,
- ),
- )
-
-proto_language_attrs = {
- "output_to_workspace": attr.bool(),
- "output_to_jar": attr.bool(),
- "output_to_library": attr.bool(),
- "output_to_libdir": attr.bool(),
- "output_file_style": attr.string(),
- "supports_pb": attr.bool(default = True),
- "pb_file_extensions": attr.string_list(),
- "pb_options": attr.string_list(),
- "pb_inputs": attr.label_list(),
- "pb_imports": attr.string_list(),
- "pb_plugin_name": attr.string(),
- "pb_plugin": attr.label(
- executable = True,
- cfg = "host",
- ),
- "pb_compile_deps": attr.label_list(),
- "pb_runtime_deps": attr.label_list(),
- "prefix": attr.label(
- providers = ["go_prefix"],
- ),
- "importmap": attr.string_dict(),
-}
-
-proto_language = rule(
- implementation = _proto_language_impl,
- attrs = proto_language_attrs,
-)
-
-def _proto_language_deps_impl(ctx):
- files = []
- exts = ctx.attr.file_extensions
-
- for dep in ctx.attr.langs:
- lang = dep.proto_language
- if ctx.attr.compile_deps:
- files += lang.pb_compile_deps
- if ctx.attr.runtime_deps:
- files += lang.pb_runtime_deps
-
- deps = []
- for file in files:
- for ext in exts:
- if file.path.endswith(ext):
- deps.append(file)
-
- return struct(
- files = depset(deps),
- )
-
-proto_language_deps = rule(
- implementation = _proto_language_deps_impl,
- attrs = {
- "langs": attr.label_list(
- providers = ["proto_language"],
- mandatory = True,
- ),
- "file_extensions": attr.string_list(mandatory = True),
- "compile_deps": attr.bool(default = True),
- "runtime_deps": attr.bool(default = False),
- },
-)
diff --git a/third_party/rules_protobuf/protobuf/rules.bzl b/third_party/rules_protobuf/protobuf/rules.bzl
deleted file mode 100644
index ecaaf19..0000000
--- a/third_party/rules_protobuf/protobuf/rules.bzl
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Compiles protobuf for ObjC.
-
-"""
-
-load(
- "//third_party/rules_protobuf/protobuf:internal/proto_compile.bzl",
- _proto_compile = "proto_compile",
-)
-load(
- "//third_party/rules_protobuf/protobuf:internal/proto_language.bzl",
- _proto_language = "proto_language",
- _proto_language_deps = "proto_language_deps",
-)
-
-proto_compile = _proto_compile
-proto_language = _proto_language
-proto_language_deps = _proto_language_deps
diff --git a/tink_base_deps.bzl b/tink_base_deps.bzl
index c434913..9b75246 100644
--- a/tink_base_deps.bzl
+++ b/tink_base_deps.bzl
@@ -48,7 +48,7 @@
name = "google_root_pem",
executable = 0,
urls = ["https://pki.goog/roots.pem"],
- sha256 = "7f03c894282e3fc39105466a8ee5055ffd05e79dfd4010360117078afbfa68bd",
+ sha256 = "6b1ad80fb0b67022b23a965429740c7643c50583d0f16e0a9f1357cd16d2255a",
)
# proto
@@ -67,14 +67,14 @@
# Remote Build Execution
if not native.existing_rule("bazel_toolchains"):
- # Latest bazel_toolchains package on 2020-02-21
+ # Latest bazel_toolchains package on 2020-06-02
http_archive(
name = "bazel_toolchains",
- sha256 = "4d348abfaddbcee0c077fc51bb1177065c3663191588ab3d958f027cbfe1818b",
- strip_prefix = "bazel-toolchains-2.1.0",
+ sha256 = "db48eed61552e25d36fe051a65d2a329cc0fb08442627e8f13960c5ab087a44e",
+ strip_prefix = "bazel-toolchains-3.2.0",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/2.1.0.tar.gz",
- "https://github.com/bazelbuild/bazel-toolchains/archive/2.1.0.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/releases/download/3.2.0/bazel-toolchains-3.2.0.tar.gz",
+ "https://github.com/bazelbuild/bazel-toolchains/archive/3.2.0.tar.gz",
],
)
if not native.existing_rule("wycheproof"):
diff --git a/tools/objc.bzl b/tools/objc.bzl
deleted file mode 100644
index 77588b9..0000000
--- a/tools/objc.bzl
+++ /dev/null
@@ -1,68 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Compiles protobuf for ObjC.
-
-This tool uses https://github.com/pubref/rules_protobuf.
-"""
-
-# The actual rule which does the filtering.
-def _do_filter_impl(ctx):
- return struct(
- files = depset([f for f in ctx.files.srcs if f.path.endswith(ctx.attr.suffix)]),
- )
-
-_do_filter = rule(
- attrs = {
- "srcs": attr.label_list(
- mandatory = True,
- allow_files = True,
- ),
- "suffix": attr.string(
- mandatory = True,
- ),
- },
- implementation = _do_filter_impl,
-)
-
-# A convenient macro to wrap the custom rule and objc_library.
-def tink_objc_proto_library(name, srcs, **kwargs):
- """
- Compiles ObjC proto libaries in srcs into a single library.
-
- Args:
- name: the name of the output library
- srcs: the list of ObjC proto libraries, which are generated using
- objc_proto_compile in rules_protobuf.
- """
-
- _do_filter(
- name = "%s_hdrs" % name,
- visibility = ["//visibility:private"],
- # srcs = hdrs,
- srcs = srcs,
- suffix = ".pbobjc.h",
- )
- _do_filter(
- name = "%s_srcs" % name,
- visibility = ["//visibility:private"],
- srcs = srcs,
- suffix = ".pbobjc.m",
- )
- native.objc_library(
- name = name,
- srcs = [":%s_srcs" % name],
- hdrs = [":%s_hdrs" % name],
- copts = ["-fno-objc-arc"],
- deps = ["@com_google_protobuf//:objectivec"],
- **kwargs
- )
diff --git a/tools/testing/BUILD.bazel b/tools/testing/BUILD.bazel
index 2573616..7061c26 100644
--- a/tools/testing/BUILD.bazel
+++ b/tools/testing/BUILD.bazel
@@ -1,9 +1,9 @@
+load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+
package(default_visibility = ["//:__subpackages__"])
licenses(["notice"])
-load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
java_library(
name = "cli_util",
testonly = 1,
@@ -12,7 +12,11 @@
],
javacopts = JAVACOPTS_OSS,
deps = [
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:binary_keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:binary_keyset_writer",
+ "@tink_java//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
],
)
@@ -22,8 +26,8 @@
srcs = ["java/com/google/crypto/tink/testing/CompareKeysets.java"],
javacopts = JAVACOPTS_OSS,
deps = [
- "@tink_java//src/main/java/com/google/crypto/tink:privileged_registry",
"@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink:privileged_registry",
],
)
@@ -37,8 +41,8 @@
":cli_util",
":compare_keysets",
"@tink_java//:cleartext_keyset_handle",
- "@tink_java//src/main/java/com/google/crypto/tink:core",
- "@tink_java//src/main/java/com/google/crypto/tink/config",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
],
)
@@ -51,7 +55,7 @@
javacopts = JAVACOPTS_OSS,
main_class = "com.google.crypto.tink.testing.VersionCli",
deps = [
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:core",
],
)
@@ -65,12 +69,14 @@
main_class = "com.google.crypto.tink.testing.AeadCli",
deps = [
":cli_util",
- "@tink_java//:awskms",
- "@tink_java//:gcpkms",
- "@tink_java//:testonly",
- "@tink_java//:testutil",
- "@tink_java//src/main/java/com/google/crypto/tink",
- "@tink_java//src/main/java/com/google/crypto/tink/aead",
+ "@tink_java//src/main/java/com/google/crypto/tink:aead",
+ "@tink_java//src/main/java/com/google/crypto/tink:kms_client",
+ "@tink_java//src/main/java/com/google/crypto/tink:kms_clients",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aead_config",
+ "@tink_java//src/main/java/com/google/crypto/tink/integration/awskms:aws_kms_client",
+ "@tink_java//src/main/java/com/google/crypto/tink/integration/gcpkms:gcp_kms_client",
+ "@tink_java//src/main/java/com/google/crypto/tink/testing:test_util",
],
)
@@ -84,7 +90,8 @@
main_class = "com.google.crypto.tink.testing.DeterministicAeadCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:deterministic_aead",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
@@ -98,7 +105,8 @@
main_class = "com.google.crypto.tink.testing.StreamingAeadCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink:streaming_aead",
],
)
@@ -112,7 +120,8 @@
main_class = "com.google.crypto.tink.testing.MacCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:mac",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
@@ -126,7 +135,8 @@
main_class = "com.google.crypto.tink.testing.HybridEncryptCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
@@ -140,7 +150,8 @@
main_class = "com.google.crypto.tink.testing.HybridDecryptCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
@@ -154,7 +165,8 @@
main_class = "com.google.crypto.tink.testing.PublicKeySignCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_sign",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
@@ -168,20 +180,7 @@
main_class = "com.google.crypto.tink.testing.PublicKeyVerifyCli",
deps = [
":cli_util",
- "@tink_java//:testonly",
- ],
-)
-
-py_library(
- name = "supported_key_types",
- testonly = 1,
- srcs = ["supported_key_types.py"],
- deps = [
- "@tink_py//tink/aead",
- "@tink_py//tink/daead",
- "@tink_py//tink/hybrid",
- "@tink_py//tink/mac",
- "@tink_py//tink/signature",
- "@tink_py//tink/proto:tink_py_pb2",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_verify",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
],
)
diff --git a/tools/testing/cross_language/BUILD.bazel b/tools/testing/cross_language/BUILD.bazel
index 5a34468..321073f 100644
--- a/tools/testing/cross_language/BUILD.bazel
+++ b/tools/testing/cross_language/BUILD.bazel
@@ -13,19 +13,6 @@
)
sh_test(
- name = "keyset_reader_writer_test",
- size = "small",
- srcs = [
- "keyset_reader_writer_test.sh",
- ],
- data = [
- ":test_lib",
- "//testing/cc:keyset_reader_writer_cli",
- "//tinkey",
- ],
-)
-
-sh_test(
name = "version_test",
size = "medium",
srcs = [
@@ -39,21 +26,6 @@
],
)
-py_test(
- name = "aead_test",
- srcs = ["aead_test.py"],
- python_version = "PY3",
- srcs_version = "PY3",
- deps = [
- requirement("absl-py"),
- "//testing:supported_key_types",
- "//testing/cross_language/util:cli_aead",
- "//testing/cross_language/util:keyset_manager",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/aead",
- ],
-)
-
sh_test(
name = "aead_envelope_test",
size = "medium",
@@ -74,21 +46,6 @@
tags = ["no_rbe"],
)
-py_test(
- name = "deterministic_aead_test",
- srcs = ["deterministic_aead_test.py"],
- python_version = "PY3",
- srcs_version = "PY3",
- deps = [
- requirement("absl-py"),
- "//testing:supported_key_types",
- "//testing/cross_language/util:cli_daead",
- "//testing/cross_language/util:keyset_manager",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/daead",
- ],
-)
-
sh_test(
name = "streaming_aead_test",
size = "medium",
@@ -104,21 +61,6 @@
],
)
-py_test(
- name = "mac_test",
- srcs = ["mac_test.py"],
- python_version = "PY3",
- srcs_version = "PY3",
- deps = [
- requirement("absl-py"),
- "//testing:supported_key_types",
- "//testing/cross_language/util:cli_mac",
- "//testing/cross_language/util:keyset_manager",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/mac",
- ],
-)
-
sh_test(
name = "prf_set_test",
size = "medium",
@@ -132,33 +74,3 @@
"//tinkey",
],
)
-
-py_test(
- name = "hybrid_encryption_test",
- srcs = ["hybrid_encryption_test.py"],
- python_version = "PY3",
- srcs_version = "PY3",
- deps = [
- requirement("absl-py"),
- "//testing:supported_key_types",
- "//testing/cross_language/util:cli_hybrid",
- "//testing/cross_language/util:keyset_manager",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/hybrid",
- ],
-)
-
-py_test(
- name = "signature_test",
- srcs = ["signature_test.py"],
- python_version = "PY3",
- srcs_version = "PY3",
- deps = [
- requirement("absl-py"),
- "//testing:supported_key_types",
- "//testing/cross_language/util:cli_signature",
- "//testing/cross_language/util:keyset_manager",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/signature",
- ],
-)
diff --git a/tools/testing/cross_language/aead_test.py b/tools/testing/cross_language/aead_test.py
deleted file mode 100644
index 6a29eed..0000000
--- a/tools/testing/cross_language/aead_test.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Cross-language tests for the Aead primitive."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-
-import tink
-from tink import aead
-
-from tools.testing import supported_key_types
-from tools.testing.cross_language.util import cli_aead
-from tools.testing.cross_language.util import keyset_manager
-
-
-def setUpModule():
- aead.register()
-
-
-class AeadPythonTest(parameterized.TestCase):
-
- @parameterized.parameters(
- supported_key_types.test_cases(supported_key_types.AEAD_KEY_TYPES))
- def test_encrypt_decrypt(self, key_template_name, supported_langs):
- key_template = supported_key_types.KEY_TEMPLATE[key_template_name]
- keyset_handle = keyset_manager.new_keyset_handle(key_template)
- supported_aeads = [
- cli_aead.CliAead(lang, keyset_handle) for lang in supported_langs
- ]
- unsupported_aeads = [
- cli_aead.CliAead(lang, keyset_handle)
- for lang in cli_aead.LANGUAGES
- if lang not in supported_langs
- ]
- for p in supported_aeads:
- plaintext = (
- b'This is some plaintext message to be encrypted using key_template '
- b'%s using %s for encryption.'
- % (key_template_name.encode('utf8'), p.lang.encode('utf8')))
- associated_data = (
- b'Some associated data for %s using %s for encryption.' %
- (key_template_name.encode('utf8'), p.lang.encode('utf8')))
- ciphertext = p.encrypt(plaintext, associated_data)
- for p2 in supported_aeads:
- output = p2.decrypt(ciphertext, associated_data)
- self.assertEqual(output, plaintext)
- for p2 in unsupported_aeads:
- with self.assertRaises(tink.TinkError):
- p2.decrypt(ciphertext, associated_data)
- for p in unsupported_aeads:
- with self.assertRaises(tink.TinkError):
- p.encrypt(b'plaintext', b'associated_data')
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/keyset_reader_writer_test.sh b/tools/testing/cross_language/keyset_reader_writer_test.sh
deleted file mode 100755
index 2d25ae9..0000000
--- a/tools/testing/cross_language/keyset_reader_writer_test.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/bash
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-################################################################################
-
-
-ROOT_DIR="$TEST_SRCDIR/tools"
-CC_KEYSET_RW_CLI="$ROOT_DIR/testing/cc/keyset_reader_writer_cli"
-JAVA_KEYSET_RW_CLI="$ROOT_DIR/tinkey/tinkey"
-TEST_UTIL="$ROOT_DIR/testing/cross_language/test_util.sh"
-
-source $TEST_UTIL || exit 1
-
-#############################################################################
-### Helpers for KeysetReader and KeysetWriter-tests.
-
-# Checks cross-language compatibility of implementations of
-# KeysetReader and KeysetWriter interfaces.
-#
-# Expects as parameter an input keyset in format given by 'input_format'
-# (generated by the corresponding Java KeysetWriter).
-# Uses CC_KEYSET_RW_CLI (which is based on C++ KeysetReader/Writer)
-# to read the input and output a copy of the input keyst in format
-# specified in 'output_format'.
-keyset_reader_writer_basic_test() {
- local test_name="keyset-reader-writer-basic-test"
- local input_format="$1"
- local input_file="$2"
- local output_format="$3"
-
- local test_instance="${test_name}_${input_format}_${output_format}"
-
- echo "############ starting test $test_instance for keyset file"
- local output_file="$TEST_TMPDIR/${test_instance}_output.${output_format}"
- $CC_KEYSET_RW_CLI $input_format $input_file $output_format $output_file
-
- # Use binary representation for output comparison, as JSON representation
- # seems not to be deterministic, and the order of fields varies.
- local orig_java_keyset="$TEST_TMPDIR/${test_instance}_orig_keyset_java.bin"
- local copy_cc_keyset="$TEST_TMPDIR/${test_instance}_copy_keyset_cc.bin"
- echo "### generating JSON representation of the original keyset"
- $JAVA_KEYSET_RW_CLI convert-keyset --in-format $input_format\
- --in $input_file --out-format "BINARY" > $orig_java_keyset
- echo "### generating JSON representation of the copied keyset"
- $JAVA_KEYSET_RW_CLI convert-keyset --in-format $output_format\
- --in $output_file --out-format "BINARY" > $copy_cc_keyset
- assert_files_equal $orig_java_keyset $copy_cc_keyset
-}
-
-#############################################################################
-##### Run the actual tests.
-
-### Java BINARY, C++ BINARY
-generate_symmetric_key "AEAD-test-1" "AES128_CTR_HMAC_SHA256" "BINARY"
-keyset_reader_writer_basic_test "BINARY" $symmetric_key_file "BINARY"
-
-### Java BINARY, C++ JSON
-generate_symmetric_key "AEAD-test-2" "AES128_CTR_HMAC_SHA256" "BINARY"
-keyset_reader_writer_basic_test "BINARY" $symmetric_key_file "JSON"
-
-### Java JSON, C++ BINARY
-generate_symmetric_key "AEAD-test-3" "AES128_CTR_HMAC_SHA256" "JSON"
-keyset_reader_writer_basic_test "JSON" $symmetric_key_file "BINARY"
-
-### Java JSON, C++ JSON
-generate_symmetric_key "AEAD-test-4" "AES256_CTR_HMAC_SHA256" "JSON"
-keyset_reader_writer_basic_test "JSON" $symmetric_key_file "JSON"
diff --git a/tools/testing/cross_language/util/BUILD.bazel b/tools/testing/cross_language/util/BUILD.bazel
deleted file mode 100644
index f5fbd28..0000000
--- a/tools/testing/cross_language/util/BUILD.bazel
+++ /dev/null
@@ -1,209 +0,0 @@
-load("@rules_python//python:defs.bzl", "py_library")
-load("@pip_deps//:requirements.bzl", "requirement")
-
-package(default_visibility = ["//visibility:public"])
-
-py_library(
- name = "cli_aead",
- testonly = 1,
- srcs = [
- "cli_aead.py",
- ],
- data = [
- "//testing:aead_cli_java",
- "//testing/cc:aead_cli_cc",
- "//testing/go:aead_cli_go",
- "//testing/python:aead_cli_python",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/aead",
- ],
-)
-
-py_test(
- name = "cli_aead_test",
- srcs = ["cli_aead_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_aead",
- requirement("absl-py"),
- "@tink_py//tink:tink_python",
- "@tink_py//tink/aead",
- ],
-)
-
-py_library(
- name = "cli_daead",
- testonly = 1,
- srcs = [
- "cli_daead.py",
- ],
- data = [
- "//testing:deterministic_aead_cli_java",
- "//testing/cc:deterministic_aead_cli_cc",
- "//testing/go:deterministic_aead_cli_go",
- "//testing/python:deterministic_aead_cli_python",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/daead",
- ],
-)
-
-py_test(
- name = "cli_daead_test",
- srcs = ["cli_daead_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_daead",
- requirement("absl-py"),
- "@tink_py//tink:tink_python",
- "@tink_py//tink/daead",
- ],
-)
-
-py_library(
- name = "cli_hybrid",
- testonly = 1,
- srcs = [
- "cli_hybrid.py",
- ],
- data = [
- "//testing:hybrid_decrypt_cli_java",
- "//testing:hybrid_encrypt_cli_java",
- "//testing/cc:hybrid_decrypt_cli_cc",
- "//testing/cc:hybrid_encrypt_cli_cc",
- "//testing/go:hybrid_decrypt_cli_go",
- "//testing/go:hybrid_encrypt_cli_go",
- "//testing/python:hybrid_decrypt_cli_python",
- "//testing/python:hybrid_encrypt_cli_python",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/hybrid",
- ],
-)
-
-py_test(
- name = "cli_hybrid_test",
- srcs = ["cli_hybrid_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_hybrid",
- requirement("absl-py"),
- "@tink_py//tink:tink_python",
- "@tink_py//tink/hybrid",
- ],
-)
-
-py_library(
- name = "cli_mac",
- testonly = 1,
- srcs = [
- "cli_mac.py",
- ],
- data = [
- "//testing:mac_cli_java",
- "//testing/cc:mac_cli_cc",
- "//testing/go:mac_cli_go",
- "//testing/python:mac_cli_python",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/mac",
- ],
-)
-
-py_test(
- name = "cli_mac_test",
- srcs = ["cli_mac_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_mac",
- requirement("absl-py"),
- "@tink_py//tink:tink_python",
- "@tink_py//tink/mac",
- ],
-)
-
-py_library(
- name = "cli_signature",
- testonly = 1,
- srcs = [
- "cli_signature.py",
- ],
- data = [
- "//testing:public_key_sign_cli_java",
- "//testing:public_key_verify_cli_java",
- "//testing/cc:public_key_sign_cli_cc",
- "//testing/cc:public_key_verify_cli_cc",
- "//testing/go:public_key_sign_cli_go",
- "//testing/go:public_key_verify_cli_go",
- "//testing/python:public_key_sign_cli_python",
- "//testing/python:public_key_verify_cli_python",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/mac",
- ],
-)
-
-py_test(
- name = "cli_signature_test",
- srcs = ["cli_signature_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_signature",
- requirement("absl-py"),
- "@tink_py//tink:tink_python",
- "@tink_py//tink/signature",
- ],
-)
-
-py_library(
- name = "cli_tinkey",
- testonly = 1,
- srcs = [
- "cli_tinkey.py",
- ],
- data = [
- "//tinkey",
- ],
- deps = [
- "@tink_py//tink:cleartext_keyset_handle",
- "@tink_py//tink:tink_python",
- ],
-)
-
-py_test(
- name = "cli_tinkey_test",
- srcs = ["cli_tinkey_test.py"],
- srcs_version = "PY3",
- deps = [
- ":cli_aead",
- ":cli_daead",
- ":cli_hybrid",
- ":cli_mac",
- ":cli_tinkey",
- requirement("absl-py"),
- ],
-)
-
-py_library(
- name = "keyset_manager",
- testonly = 1,
- srcs = [
- "keyset_manager.py",
- ],
- deps = [
- ":cli_tinkey",
- "@tink_py//tink:tink_python",
- "@tink_py//tink/proto:tink_py_pb2",
- ],
-)
diff --git a/tools/testing/cross_language/util/cli_aead.py b/tools/testing/cross_language/util/cli_aead.py
deleted file mode 100644
index a815449..0000000
--- a/tools/testing/cross_language/util/cli_aead.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Wraps an AEAD CLI into a Python Tink Aead class."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import aead
-from tink import cleartext_keyset_handle
-
-from typing import Text
-
-
-# All languages that have an AEAD CLI.
-LANGUAGES = ('cc', 'go', 'java', 'python')
-
-# Path are relative to tools directory.
-_AEAD_CLI_PATHS = {
- 'cc': 'testing/cc/aead_cli_cc',
- 'go': 'testing/go/aead_cli_go',
- 'java': 'testing/aead_cli_java',
- 'python': 'testing/python/aead_cli_python',
-}
-
-
-def _tools_path() -> Text:
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-class CliAead(aead.Aead):
- """Wraps a AEAD CLI binary into a Python AEAD primitive."""
-
- def __init__(self, lang: Text, keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _AEAD_CLI_PATHS[lang])
- self._keyset_handle = keyset_handle
-
- def _run(self, operation: Text, input_data: bytes,
- associated_data: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- keyset_filename = os.path.join(tmpdir, 'keyset_file')
- input_filename = os.path.join(tmpdir, 'input_file')
- associated_data_filename = os.path.join(tmpdir, 'associated_data_file')
- output_filename = os.path.join(tmpdir, 'output_file')
- with open(keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._keyset_handle)
- with open(input_filename, 'wb') as f:
- f.write(input_data)
- with open(associated_data_filename, 'wb') as f:
- f.write(associated_data)
- try:
- unused_return_value = subprocess.check_output([
- self._cli, keyset_filename, operation,
- input_filename, associated_data_filename, output_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(output_filename, 'rb') as f:
- output_data = f.read()
- return output_data
-
- def encrypt(self, plaintext: bytes, associated_data: bytes) -> bytes:
- return self._run('encrypt', plaintext, associated_data)
-
- def decrypt(self, ciphertext: bytes, associated_data: bytes) -> bytes:
- return self._run('decrypt', ciphertext, associated_data)
diff --git a/tools/testing/cross_language/util/cli_aead_test.py b/tools/testing/cross_language/util/cli_aead_test.py
deleted file mode 100644
index c56759c..0000000
--- a/tools/testing/cross_language/util/cli_aead_test.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.cli_aead."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-import tink
-from tink import aead
-from tools.testing.cross_language.util import cli_aead
-
-
-def setUpModule():
- aead.register()
-
-
-class CliAeadTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_aead.LANGUAGES)
- def test_encrypt_decrypt_success(self, lang):
- keyset_handle = tink.new_keyset_handle(
- aead.aead_key_templates.AES128_GCM)
- primitive = cli_aead.CliAead(lang, keyset_handle)
- plaintext = b'plaintext'
- associated_data = b'associated_data'
- ciphertext = primitive.encrypt(plaintext, associated_data)
- output = primitive.decrypt(ciphertext, associated_data)
- self.assertEqual(output, plaintext)
-
- @parameterized.parameters(*cli_aead.LANGUAGES)
- def test_invalid_decrypt_raises_error(self, lang):
- keyset_handle = tink.new_keyset_handle(
- aead.aead_key_templates.AES128_GCM)
- primitive = cli_aead.CliAead(lang, keyset_handle)
- with self.assertRaises(tink.TinkError):
- primitive.decrypt(b'invalid ciphertext', b'associated_data')
-
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/cli_daead.py b/tools/testing/cross_language/util/cli_daead.py
deleted file mode 100644
index d1bc265..0000000
--- a/tools/testing/cross_language/util/cli_daead.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Wraps a Deterministic AEAD CLI into a Python Tink DeterministicAead class."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import cleartext_keyset_handle
-from tink import daead
-
-from typing import Text
-
-# All languages that have an Deterministic AEAD CLI.
-LANGUAGES = ('cc', 'go', 'java', 'python')
-
-# Path are relative to tools directory.
-_DAEAD_CLI_PATHS = {
- 'cc': 'testing/cc/deterministic_aead_cli_cc',
- 'go': 'testing/go/deterministic_aead_cli_go',
- 'java': 'testing/deterministic_aead_cli_java',
- 'python': 'testing/python/deterministic_aead_cli_python',
-}
-
-
-def _tools_path() -> Text:
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-class CliDeterministicAead(daead.DeterministicAead):
- """Wraps Deterministic AEAD CLI binary into a DeterministicAead primitive."""
-
- def __init__(self, lang: Text, keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _DAEAD_CLI_PATHS[lang])
- self._keyset_handle = keyset_handle
-
- def _run(self, operation: Text, input_data: bytes,
- associated_data: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- keyset_filename = os.path.join(tmpdir, 'keyset_file')
- input_filename = os.path.join(tmpdir, 'input_file')
- associated_data_filename = os.path.join(tmpdir, 'associated_data_file')
- output_filename = os.path.join(tmpdir, 'output_file')
- with open(keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._keyset_handle)
- with open(input_filename, 'wb') as f:
- f.write(input_data)
- with open(associated_data_filename, 'wb') as f:
- f.write(associated_data)
- try:
- unused_return_value = subprocess.check_output([
- self._cli, keyset_filename, operation,
- input_filename, associated_data_filename, output_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(output_filename, 'rb') as f:
- output_data = f.read()
- return output_data
-
- def encrypt_deterministically(
- self, plaintext: bytes, associated_data: bytes) -> bytes:
- return self._run('encryptdeterministically', plaintext, associated_data)
-
- def decrypt_deterministically(
- self, ciphertext: bytes, associated_data: bytes) -> bytes:
- return self._run('decryptdeterministically', ciphertext, associated_data)
-
diff --git a/tools/testing/cross_language/util/cli_daead_test.py b/tools/testing/cross_language/util/cli_daead_test.py
deleted file mode 100644
index 7d7d9a9..0000000
--- a/tools/testing/cross_language/util/cli_daead_test.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.cli_daead."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-
-import tink
-from tink import daead
-
-from tools.testing.cross_language.util import cli_daead
-
-
-def setUpModule():
- daead.register()
-
-
-class CliDaeadTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_daead.LANGUAGES)
- def test_encrypt_decrypt_success(self, lang):
- keyset_handle = tink.new_keyset_handle(
- daead.deterministic_aead_key_templates.AES256_SIV)
- p = cli_daead.CliDeterministicAead(lang, keyset_handle)
- plaintext = b'plaintext'
- associated_data = b'associated_data'
- ciphertext = p.encrypt_deterministically(plaintext, associated_data)
- output = p.decrypt_deterministically(ciphertext, associated_data)
- self.assertEqual(output, plaintext)
-
- @parameterized.parameters(*cli_daead.LANGUAGES)
- def test_invalid_decrypt_raises_error(self, lang):
- keyset_handle = tink.new_keyset_handle(
- daead.deterministic_aead_key_templates.AES256_SIV)
- p = cli_daead.CliDeterministicAead(lang, keyset_handle)
- with self.assertRaises(tink.TinkError):
- p.decrypt_deterministically(b'invalid ciphertext', b'associated_data')
-
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/cli_hybrid.py b/tools/testing/cross_language/util/cli_hybrid.py
deleted file mode 100644
index 1d3e597..0000000
--- a/tools/testing/cross_language/util/cli_hybrid.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Wraps Hybrid Encryption CLIs into a Python Tink classes."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import cleartext_keyset_handle
-from tink import hybrid
-
-from typing import Text
-
-# All languages that have a Hybrid Encryption CLI.
-LANGUAGES = ('cc', 'go', 'java', 'python')
-
-# Path are relative to tools directory.
-_ENCRYPT_CLI_PATHS = {
- 'cc': 'testing/cc/hybrid_encrypt_cli_cc',
- 'go': 'testing/go/hybrid_encrypt_cli_go',
- 'java': 'testing/hybrid_encrypt_cli_java',
- 'python': 'testing/python/hybrid_encrypt_cli_python',
-}
-
-_DECRYPT_CLI_PATHS = {
- 'cc': 'testing/cc/hybrid_decrypt_cli_cc',
- 'go': 'testing/go/hybrid_decrypt_cli_go',
- 'java': 'testing/hybrid_decrypt_cli_java',
- 'python': 'testing/python/hybrid_decrypt_cli_python',
-}
-
-
-def _tools_path() -> Text:
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-class CliHybridEncrypt(hybrid.HybridEncrypt):
- """Wraps a HybridEncrypt CLI binary into a Python primitive."""
-
- def __init__(self, lang: Text,
- public_keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _ENCRYPT_CLI_PATHS[lang])
- self._public_keyset_handle = public_keyset_handle
-
- def encrypt(self, plaintext: bytes, context_info: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- public_keyset_filename = os.path.join(tmpdir, 'public_keyset_file')
- with open(public_keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._public_keyset_handle)
- plaintext_filename = os.path.join(tmpdir, 'plaintext_file')
- with open(plaintext_filename, 'wb') as f:
- f.write(plaintext)
- context_info_filename = os.path.join(tmpdir, 'context_info_file')
- with open(context_info_filename, 'wb') as f:
- f.write(context_info)
- ciphertext_filename = os.path.join(tmpdir, 'ciphertext_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, public_keyset_filename, plaintext_filename,
- context_info_filename, ciphertext_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(ciphertext_filename, 'rb') as f:
- ciphertext = f.read()
- return ciphertext
-
-
-class CliHybridDecrypt(hybrid.HybridDecrypt):
- """Wraps a HybridDecrypt CLI binary into a Python primitive."""
-
- def __init__(self, lang: Text,
- private_keyset_handle: tink.KeysetHandle) -> None:
- self._cli = os.path.join(_tools_path(), _DECRYPT_CLI_PATHS[lang])
- self._private_keyset_handle = private_keyset_handle
-
- def decrypt(self, ciphertext: bytes, context_info: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- private_keyset_filename = os.path.join(tmpdir, 'private_keyset_file')
- with open(private_keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._private_keyset_handle)
- ciphertext_filename = os.path.join(tmpdir, 'ciphertext_file')
- with open(ciphertext_filename, 'wb') as f:
- f.write(ciphertext)
- context_info_filename = os.path.join(tmpdir, 'context_info_file')
- with open(context_info_filename, 'wb') as f:
- f.write(context_info)
- decrypted_filename = os.path.join(tmpdir, 'decrypted_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, private_keyset_filename, ciphertext_filename,
- context_info_filename, decrypted_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(decrypted_filename, 'rb') as f:
- plaintext = f.read()
- return plaintext
diff --git a/tools/testing/cross_language/util/cli_hybrid_test.py b/tools/testing/cross_language/util/cli_hybrid_test.py
deleted file mode 100644
index 4d5ea5e..0000000
--- a/tools/testing/cross_language/util/cli_hybrid_test.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.cli_hybrid."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-
-import tink
-from tink import hybrid
-
-from tools.testing.cross_language.util import cli_hybrid
-
-
-def setUpModule():
- hybrid.register()
-
-
-class CliHybridTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_hybrid.LANGUAGES)
- def test_encrypt_decrypt_success(self, lang):
- private_keyset_handle = tink.new_keyset_handle(
- hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)
- public_keyset_handle = private_keyset_handle.public_keyset_handle()
- enc = cli_hybrid.CliHybridEncrypt(lang, public_keyset_handle)
- dec = cli_hybrid.CliHybridDecrypt(lang, private_keyset_handle)
- plaintext = b'plaintext'
- context_info = b'context_info'
- ciphertext = enc.encrypt(plaintext, context_info)
- output = dec.decrypt(ciphertext, context_info)
- self.assertEqual(output, plaintext)
-
- @parameterized.parameters(*cli_hybrid.LANGUAGES)
- def test_invalid_decrypt_raises_error(self, lang):
- private_keyset_handle = tink.new_keyset_handle(
- hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)
- dec = cli_hybrid.CliHybridDecrypt(lang, private_keyset_handle)
- with self.assertRaises(tink.TinkError):
- dec.decrypt(b'invalid ciphertext', b'context_info')
-
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/cli_mac.py b/tools/testing/cross_language/util/cli_mac.py
deleted file mode 100644
index 4b485e3..0000000
--- a/tools/testing/cross_language/util/cli_mac.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Wraps a AEAD CLI into a Python Tink Aead class."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import cleartext_keyset_handle
-from tink import mac
-
-from typing import Text
-
-# All languages that have an AEAD CLI.
-LANGUAGES = ('cc', 'go', 'java', 'python')
-
-# Path are relative to tools directory.
-_MAC_CLI_PATHS = {
- 'cc': 'testing/cc/mac_cli_cc',
- 'go': 'testing/go/mac_cli_go',
- 'java': 'testing/mac_cli_java',
- 'python': 'testing/python/mac_cli_python',
-}
-
-
-def _tools_path() -> Text:
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-class CliMac(mac.Mac):
- """Wraps a Mac CLI binary into a Python primitive."""
-
- def __init__(self, lang: Text, keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _MAC_CLI_PATHS[lang])
- self._keyset_handle = keyset_handle
-
- def compute_mac(self, data: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- keyset_filename = os.path.join(tmpdir, 'keyset_file')
- with open(keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._keyset_handle)
- data_filename = os.path.join(tmpdir, 'data_file')
- with open(data_filename, 'wb') as f:
- f.write(data)
- mac_filename = os.path.join(tmpdir, 'mac_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, keyset_filename, 'compute', data_filename, mac_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(mac_filename, 'rb') as f:
- mac_value = f.read()
- return mac_value
-
- def verify_mac(self, mac_value: bytes, data: bytes) -> None:
- with tempfile.TemporaryDirectory() as tmpdir:
- keyset_filename = os.path.join(tmpdir, 'keyset_file')
- with open(keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._keyset_handle)
- data_filename = os.path.join(tmpdir, 'data_file')
- with open(data_filename, 'wb') as f:
- f.write(data)
- mac_filename = os.path.join(tmpdir, 'mac_file')
- with open(mac_filename, 'wb') as f:
- f.write(mac_value)
- result_filename = os.path.join(tmpdir, 'result_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, keyset_filename, 'verify',
- data_filename, mac_filename, result_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(result_filename, 'rb') as f:
- result = f.read()
- if result != b'valid':
- raise tink.TinkError('verification failed')
- return None
diff --git a/tools/testing/cross_language/util/cli_mac_test.py b/tools/testing/cross_language/util/cli_mac_test.py
deleted file mode 100644
index eebcc77..0000000
--- a/tools/testing/cross_language/util/cli_mac_test.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.cli_mac."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-
-import tink
-from tink import mac
-
-from tools.testing.cross_language.util import cli_mac
-
-
-def setUpModule():
- mac.register()
-
-
-class MacCliWrapperTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_mac.LANGUAGES)
- def test_mac_success(self, lang):
- keyset_handle = tink.new_keyset_handle(
- mac.mac_key_templates.HMAC_SHA256_128BITTAG)
- mac_primitive = cli_mac.CliMac(lang, keyset_handle)
- data = b'data'
- mac_value = mac_primitive.compute_mac(data)
- self.assertIsNone(mac_primitive.verify_mac(mac_value, data))
-
- @parameterized.parameters(*cli_mac.LANGUAGES)
- def test_mac_wrong(self, lang):
- keyset_handle = tink.new_keyset_handle(
- mac.mac_key_templates.HMAC_SHA256_128BITTAG)
- mac_primitive = cli_mac.CliMac(lang, keyset_handle)
- with self.assertRaisesRegex(tink.TinkError, 'verification failed'):
- mac_primitive.verify_mac(b'0123456789ABCDEF', b'data')
-
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/cli_signature.py b/tools/testing/cross_language/util/cli_signature.py
deleted file mode 100644
index e3c2c99..0000000
--- a/tools/testing/cross_language/util/cli_signature.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Wraps Sign and Verify CLIs into a Python Tink signature classes."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import cleartext_keyset_handle
-from tink import signature
-
-from typing import Text
-
-# All languages that have an AEAD CLI.
-LANGUAGES = ('cc', 'go', 'java', 'python')
-
-# Path are relative to tools directory.
-_SIGN_CLI_PATHS = {
- 'cc': 'testing/cc/public_key_sign_cli_cc',
- 'go': 'testing/go/public_key_sign_cli_go',
- 'java': 'testing/public_key_sign_cli_java',
- 'python': 'testing/python/public_key_sign_cli_python',
-}
-
-_VERIFY_CLI_PATHS = {
- 'cc': 'testing/cc/public_key_verify_cli_cc',
- 'go': 'testing/go/public_key_verify_cli_go',
- 'java': 'testing/public_key_verify_cli_java',
- 'python': 'testing/python/public_key_verify_cli_python',
-}
-
-
-def _tools_path() -> Text:
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-class CliPublicKeySign(signature.PublicKeySign):
- """Wraps a PublicKeySign CLI binary into a Python primitive."""
-
- def __init__(self, lang: Text,
- private_keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _SIGN_CLI_PATHS[lang])
- self._private_keyset_handle = private_keyset_handle
-
- def sign(self, message: bytes) -> bytes:
- with tempfile.TemporaryDirectory() as tmpdir:
- private_keyset_filename = os.path.join(tmpdir, 'private_keyset_file')
- with open(private_keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._private_keyset_handle)
- message_filename = os.path.join(tmpdir, 'message_filename')
- with open(message_filename, 'wb') as f:
- f.write(message)
- output_filename = os.path.join(tmpdir, 'output_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, private_keyset_filename, message_filename,
- output_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(output_filename, 'rb') as f:
- output = f.read()
- return output
-
-
-class CliPublicKeyVerify(signature.PublicKeyVerify):
- """Wraps a PublicKeyVerify CLI binary into a Python primitive."""
-
- def __init__(self, lang: Text,
- public_keyset_handle: tink.KeysetHandle) -> None:
- self.lang = lang
- self._cli = os.path.join(_tools_path(), _VERIFY_CLI_PATHS[lang])
- self._public_keyset_handle = public_keyset_handle
-
- def verify(self, sign: bytes, data: bytes) -> None:
- with tempfile.TemporaryDirectory() as tmpdir:
- public_keyset_filename = os.path.join(tmpdir, 'public_keyset_file')
- with open(public_keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), self._public_keyset_handle)
- signature_filename = os.path.join(tmpdir, 'signature_file')
- with open(signature_filename, 'wb') as f:
- f.write(sign)
- message_filename = os.path.join(tmpdir, 'message_file')
- with open(message_filename, 'wb') as f:
- f.write(data)
- output_filename = os.path.join(tmpdir, 'output_file')
- try:
- unused_return_value = subprocess.check_output([
- self._cli, public_keyset_filename, signature_filename,
- message_filename, output_filename
- ])
- except subprocess.CalledProcessError as e:
- raise tink.TinkError(e)
- with open(output_filename, 'rb') as f:
- output = f.read()
- if output != b'valid':
- raise tink.TinkError('verification failed')
- return None
diff --git a/tools/testing/cross_language/util/cli_signature_test.py b/tools/testing/cross_language/util/cli_signature_test.py
deleted file mode 100644
index d6007bc..0000000
--- a/tools/testing/cross_language/util/cli_signature_test.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2019 Google LLC.
-#
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.cli_signature."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-
-import tink
-from tink import signature
-
-from tools.testing.cross_language.util import cli_signature
-
-
-def setUpModule():
- signature.register()
-
-
-class CliSignatureTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_signature.LANGUAGES)
- def test_sign_verify_success(self, lang):
- private_keyset_handle = tink.new_keyset_handle(
- signature.signature_key_templates.ECDSA_P256)
- public_keyset_handle = private_keyset_handle.public_keyset_handle()
- signer = cli_signature.CliPublicKeySign(lang, private_keyset_handle)
- verifier = cli_signature.CliPublicKeyVerify(lang, public_keyset_handle)
- message = b'message'
- sign = signer.sign(message)
- self.assertIsNone(verifier.verify(sign, message))
-
- @parameterized.parameters(*cli_signature.LANGUAGES)
- def test_invalid_decrypt_raises_error(self, lang):
- private_keyset_handle = tink.new_keyset_handle(
- signature.signature_key_templates.ECDSA_P256)
- public_keyset_handle = private_keyset_handle.public_keyset_handle()
- verifier = cli_signature.CliPublicKeyVerify(lang, public_keyset_handle)
- with self.assertRaises(tink.TinkError):
- verifier.verify(b'invalid signature', b'message')
-
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/cli_tinkey.py b/tools/testing/cross_language/util/cli_tinkey.py
deleted file mode 100644
index 6bdff99..0000000
--- a/tools/testing/cross_language/util/cli_tinkey.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Python wrapper for Tinkey CLI."""
-
-# Placeholder for import for type annotations
-
-import os
-import subprocess
-import tempfile
-
-import tink
-from tink import cleartext_keyset_handle
-
-AEAD_KEY_TEMPLATES = ('AES128_GCM', 'AES256_GCM', 'AES128_CTR_HMAC_SHA256',
- 'AES256_CTR_HMAC_SHA256', 'XCHACHA20_POLY1305',
- 'AES128_EAX', 'AES256_EAX', 'CHACHA20_POLY1305')
-
-DAEAD_KEY_TEMPLATE = 'AES256_SIV'
-
-HYBRID_KEY_TEMPLATES = (
- 'ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256',
- 'ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM')
-
-MAC_KEY_TEMPLATES = ('HMAC_SHA256_128BITTAG', 'HMAC_SHA256_256BITTAG',
- 'HMAC_SHA512_256BITTAG', 'HMAC_SHA512_512BITTAG')
-
-# Path is relative to tools directory
-_TINKEY_CLI_PATH = 'tinkey/tinkey'
-
-
-def _tools_path():
- util_path = os.path.dirname(os.path.abspath(__file__))
- return os.path.dirname(os.path.dirname(os.path.dirname(util_path)))
-
-
-def generate_keyset_handle(key_template) -> tink.KeysetHandle:
- """Generates a keyset handle from a key templates."""
- with tempfile.TemporaryDirectory() as tmpdir:
- keyset_filename = os.path.join(tmpdir, 'keyset_file')
- cli_path = os.path.join(_tools_path(), _TINKEY_CLI_PATH)
- unused_return_value = subprocess.check_output([
- cli_path, 'create-keyset',
- '--key-template', key_template,
- '--out-format', 'BINARY',
- '--out', keyset_filename
- ])
- with open(keyset_filename, 'rb') as f:
- keyset_data = f.read()
- return cleartext_keyset_handle.read(tink.BinaryKeysetReader(keyset_data))
-
-
-def public_keyset_handle(private_keyset_handle) -> tink.KeysetHandle:
- """Generates a public keyset handle from a private one."""
- with tempfile.TemporaryDirectory() as tmpdir:
- cli_path = os.path.join(_tools_path(), _TINKEY_CLI_PATH)
- private_keyset_filename = os.path.join(tmpdir, 'private_keyset_file')
- with open(private_keyset_filename, 'wb') as f:
- cleartext_keyset_handle.write(
- tink.BinaryKeysetWriter(f), private_keyset_handle)
- public_keyset_filename = os.path.join(tmpdir, 'public_keyset_file')
- unused_return_value = subprocess.check_output([
- cli_path, 'create-public-keyset',
- '--in-format', 'BINARY',
- '--in', private_keyset_filename,
- '--out-format', 'BINARY',
- '--out', public_keyset_filename,
- ])
- with open(public_keyset_filename, 'rb') as f:
- public_keyset_data = f.read()
- return cleartext_keyset_handle.read(
- tink.BinaryKeysetReader(public_keyset_data))
diff --git a/tools/testing/cross_language/util/cli_tinkey_test.py b/tools/testing/cross_language/util/cli_tinkey_test.py
deleted file mode 100644
index 04ea6ed..0000000
--- a/tools/testing/cross_language/util/cli_tinkey_test.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tests for tink.tools.testing.cross_language.util.tinkey_cli."""
-
-from absl.testing import absltest
-from absl.testing import parameterized
-from tools.testing.cross_language.util import cli_aead
-from tools.testing.cross_language.util import cli_daead
-from tools.testing.cross_language.util import cli_hybrid
-from tools.testing.cross_language.util import cli_mac
-from tools.testing.cross_language.util import cli_tinkey
-
-
-class TinkeyCliWrapperTest(parameterized.TestCase):
-
- @parameterized.parameters(*cli_tinkey.AEAD_KEY_TEMPLATES)
- def test_generate_encrypt_decrypt(self, key_template):
- keyset_handle = cli_tinkey.generate_keyset_handle(key_template)
- primitive = cli_aead.CliAead('java', keyset_handle)
- plaintext = b'plaintext'
- associated_data = b'associated_data'
- ciphertext = primitive.encrypt(plaintext, associated_data)
- output = primitive.decrypt(ciphertext, associated_data)
- self.assertEqual(output, plaintext)
-
- def test_generate_encrypt_decrypt_deterministically(self):
- keyset_handle = cli_tinkey.generate_keyset_handle(
- cli_tinkey.DAEAD_KEY_TEMPLATE)
- p = cli_daead.CliDeterministicAead('java', keyset_handle)
- plaintext = b'plaintext'
- associated_data = b'associated_data'
- ciphertext = p.encrypt_deterministically(plaintext, associated_data)
- output = p.decrypt_deterministically(ciphertext, associated_data)
- self.assertEqual(output, plaintext)
-
- @parameterized.parameters(*cli_tinkey.MAC_KEY_TEMPLATES)
- def test_mac_generate_compute_verify(self, key_template):
- keyset_handle = cli_tinkey.generate_keyset_handle(key_template)
- p = cli_mac.CliMac('java', keyset_handle)
- data = b'data'
- mac_value = p.compute_mac(data)
- self.assertIsNone(p.verify_mac(mac_value, data))
-
- @parameterized.parameters(*cli_tinkey.HYBRID_KEY_TEMPLATES)
- def test_hybrid_generate_encrypt_decrypt(self, key_template):
- private_handle = cli_tinkey.generate_keyset_handle(key_template)
- public_handle = cli_tinkey.public_keyset_handle(private_handle)
- enc = cli_hybrid.CliHybridEncrypt('java', public_handle)
- dec = cli_hybrid.CliHybridDecrypt('java', private_handle)
- plaintext = b'plaintext'
- context_info = b'context_info'
- ciphertext = enc.encrypt(plaintext, context_info)
- output = dec.decrypt(ciphertext, context_info)
- self.assertEqual(output, plaintext)
-
-if __name__ == '__main__':
- absltest.main()
diff --git a/tools/testing/cross_language/util/keyset_manager.py b/tools/testing/cross_language/util/keyset_manager.py
deleted file mode 100644
index 3c31a89..0000000
--- a/tools/testing/cross_language/util/keyset_manager.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Python implementation of a KeysetManager."""
-
-# Placeholder for import for type annotations
-
-import tink
-from tink.proto import tink_pb2
-from tools.testing.cross_language.util import cli_tinkey
-
-
-_CHACHA20_POLY1305_KEY_TYPES = (
- 'type.googleapis.com/google.crypto.tink.ChaCha20Poly1305Key')
-
-
-def new_keyset_handle(key_template: tink_pb2.KeyTemplate) -> tink.KeysetHandle:
- if key_template.type_url == _CHACHA20_POLY1305_KEY_TYPES:
- return cli_tinkey.generate_keyset_handle('CHACHA20_POLY1305')
- return tink.new_keyset_handle(key_template)
diff --git a/tools/testing/javatests/com/google/crypto/tink/testing/BUILD.bazel b/tools/testing/javatests/com/google/crypto/tink/testing/BUILD.bazel
index 31f301a..33adfbc 100644
--- a/tools/testing/javatests/com/google/crypto/tink/testing/BUILD.bazel
+++ b/tools/testing/javatests/com/google/crypto/tink/testing/BUILD.bazel
@@ -7,10 +7,10 @@
size = "small",
srcs = ["CompareKeysetsTest.java"],
deps = [
- "@tink_java//src/main/java/com/google/crypto/tink/aead",
- "@tink_java//src/main/java/com/google/crypto/tink/testing:test_util",
- "@tink_java//proto:tink_java_proto",
"//testing:compare_keysets",
"@maven//:junit_junit",
+ "@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aes_gcm_key_manager",
+ "@tink_java//src/main/java/com/google/crypto/tink/testing:test_util",
],
)
diff --git a/tools/testing/python/deterministic_aead_cli.py b/tools/testing/python/deterministic_aead_cli.py
index a1c5e8a..e179402 100644
--- a/tools/testing/python/deterministic_aead_cli.py
+++ b/tools/testing/python/deterministic_aead_cli.py
@@ -54,7 +54,8 @@
"""
with open(keyset_filename, 'rb') as keyset_file:
text = keyset_file.read()
- keyset = cleartext_keyset_handle.read(tink.BinaryKeysetReader(text))
+ keyset = cleartext_keyset_handle.read(
+ tink.BinaryKeysetReader(text))
return keyset
diff --git a/tools/tinkey/BUILD.bazel b/tools/tinkey/BUILD.bazel
index a25242d..7b3fbd7 100644
--- a/tools/tinkey/BUILD.bazel
+++ b/tools/tinkey/BUILD.bazel
@@ -1,9 +1,10 @@
+load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
+load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
+
package(default_visibility = ["//:__subpackages__"])
licenses(["notice"])
-load("@tink_java//tools/build_defs:javac.bzl", "JAVACOPTS_OSS")
-
java_library(
name = "libtinkey",
srcs = glob(
@@ -15,23 +16,37 @@
],
),
javacopts = JAVACOPTS_OSS,
+ runtime_deps = [
+ # Tinkey automatically loads these KMS clients at runtime.
+ "@tink_java//src/main/java/com/google/crypto/tink/integration/awskms:aws_kms_client",
+ "@tink_java//src/main/java/com/google/crypto/tink/integration/gcpkms:gcp_kms_client",
+ ],
deps = [
+ "@com_google_protobuf//:protobuf_javalite",
+ "@maven//:args4j_args4j",
"@tink_java//:awskms",
"@tink_java//:cleartext_keyset_handle",
"@tink_java//:gcpkms",
"@tink_java//:subtle",
- "@tink_java//src/main/java/com/google/crypto/tink",
- "@tink_java//src/main/java/com/google/crypto/tink:primitives",
- "@tink_java//src/main/java/com/google/crypto/tink/aead",
- "@tink_java//src/main/java/com/google/crypto/tink/daead",
- "@tink_java//src/main/java/com/google/crypto/tink/hybrid",
- "@tink_java//src/main/java/com/google/crypto/tink/mac",
- "@tink_java//src/main/java/com/google/crypto/tink/prf:prf_key_templates",
- "@tink_java//src/main/java/com/google/crypto/tink/signature",
- "@tink_java//src/main/java/com/google/crypto/tink/streamingaead",
"@tink_java//proto:tink_java_proto",
- "@com_google_protobuf//:protobuf_javalite",
- "@maven//:args4j_args4j",
+ "@tink_java//src/main/java/com/google/crypto/tink:aead",
+ "@tink_java//src/main/java/com/google/crypto/tink:binary_keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:binary_keyset_writer",
+ "@tink_java//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "@tink_java//src/main/java/com/google/crypto/tink:json_keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:json_keyset_writer",
+ "@tink_java//src/main/java/com/google/crypto/tink:keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:keyset_writer",
+ "@tink_java//src/main/java/com/google/crypto/tink:kms_clients",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/aead:aead_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/daead:deterministic_aead_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/mac:mac_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/prf:prf_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/signature:signature_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/streamingaead:streaming_aead_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:validators",
],
)
@@ -45,15 +60,13 @@
visibility = ["//testing:__subpackages__"],
deps = [
":libtinkey",
- "@tink_java//src/main/java/com/google/crypto/tink/config",
"@maven//:args4j_args4j",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
],
)
# tests
-load("@tink_java//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
-
java_library(
name = "generator_test",
testonly = 1,
@@ -62,11 +75,24 @@
]),
deps = [
":libtinkey",
- "@tink_java//:testonly",
- "@tink_java//:testutil",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_truth_truth",
"@maven//:junit_junit",
+ "@tink_java//proto:tink_java_proto",
+ "@tink_java//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+ "@tink_java//src/main/java/com/google/crypto/tink:config",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_decrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:hybrid_encrypt",
+ "@tink_java//src/main/java/com/google/crypto/tink:keyset_reader",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_sign",
+ "@tink_java//src/main/java/com/google/crypto/tink:public_key_verify",
+ "@tink_java//src/main/java/com/google/crypto/tink:registry_cluster",
+ "@tink_java//src/main/java/com/google/crypto/tink/config:tink_config",
+ "@tink_java//src/main/java/com/google/crypto/tink/hybrid:hybrid_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/mac:mac_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/signature:signature_key_templates",
+ "@tink_java//src/main/java/com/google/crypto/tink/subtle:random",
+ "@tink_java//src/main/java/com/google/crypto/tink/testing:test_util",
],
)
diff --git a/tools/tinkey/src/main/java/com/google/crypto/tink/tinkey/ListKeyTemplatesCommand.java b/tools/tinkey/src/main/java/com/google/crypto/tink/tinkey/ListKeyTemplatesCommand.java
index 1f64b6e..0deb7ab 100644
--- a/tools/tinkey/src/main/java/com/google/crypto/tink/tinkey/ListKeyTemplatesCommand.java
+++ b/tools/tinkey/src/main/java/com/google/crypto/tink/tinkey/ListKeyTemplatesCommand.java
@@ -16,9 +16,7 @@
package com.google.crypto.tink.tinkey;
-import com.google.crypto.tink.proto.KeyTemplate;
-
-/** Creates a new {@link KeyTemplate}. */
+/** Creates a new {@link com.google.crypto.tink.proto.KeyTemplate}. */
public class ListKeyTemplatesCommand implements Command {
@Override
diff --git a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/CreatePublicKeysetCommandTest.java b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/CreatePublicKeysetCommandTest.java
index 77646ee..8eea3ba 100644
--- a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/CreatePublicKeysetCommandTest.java
+++ b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/CreatePublicKeysetCommandTest.java
@@ -28,14 +28,10 @@
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.config.TinkConfig;
-import com.google.crypto.tink.hybrid.HybridDecryptFactory;
-import com.google.crypto.tink.hybrid.HybridEncryptFactory;
import com.google.crypto.tink.hybrid.HybridKeyTemplates;
import com.google.crypto.tink.proto.EncryptedKeyset;
import com.google.crypto.tink.proto.KeyTemplate;
import com.google.crypto.tink.proto.Keyset;
-import com.google.crypto.tink.signature.PublicKeySignFactory;
-import com.google.crypto.tink.signature.PublicKeyVerifyFactory;
import com.google.crypto.tink.signature.SignatureKeyTemplates;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil;
@@ -161,10 +157,10 @@
private void assertHybrid(KeysetReader privateReader, KeysetReader publicReader)
throws Exception {
- HybridDecrypt decrypter = HybridDecryptFactory.getPrimitive(
- CleartextKeysetHandle.read(privateReader));
- HybridEncrypt encrypter = HybridEncryptFactory.getPrimitive(
- CleartextKeysetHandle.read(publicReader));
+ KeysetHandle privateHandle = CleartextKeysetHandle.read(privateReader);
+ HybridDecrypt decrypter = privateHandle.getPrimitive(HybridDecrypt.class);
+ KeysetHandle publicHandle = CleartextKeysetHandle.read(publicReader);
+ HybridEncrypt encrypter = publicHandle.getPrimitive(HybridEncrypt.class);
byte[] message = Random.randBytes(10);
byte[] contextInfo = Random.randBytes(20);
@@ -175,10 +171,10 @@
private void assertSignature(KeysetReader privateReader, KeysetReader publicReader)
throws Exception {
byte[] message = Random.randBytes(10);
- PublicKeySign signer = PublicKeySignFactory.getPrimitive(
- CleartextKeysetHandle.read(privateReader));
- PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(
- CleartextKeysetHandle.read(publicReader));
+ KeysetHandle privateHandle = CleartextKeysetHandle.read(privateReader);
+ PublicKeySign signer = privateHandle.getPrimitive(PublicKeySign.class);
+ KeysetHandle publicHandle = CleartextKeysetHandle.read(publicReader);
+ PublicKeyVerify verifier = publicHandle.getPrimitive(PublicKeyVerify.class);
verifier.verify(signer.sign(message), message);
}
@@ -192,8 +188,6 @@
case SIGNATURE:
assertSignature(privateReader, publicReader);
break;
- default:
- throw new Exception("not supported: " + type);
}
}
}