From 9858eaa5fb8edb6884e8b33adab16b8fa49ce26d Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sun, 24 May 2020 10:16:53 +0200 Subject: [PATCH] First steps --- multiplatform-crypto-api/build.gradle.kts | 418 +++++ multiplatform-crypto-api/package-lock.json | 201 +++ multiplatform-crypto-api/package.json | 15 + .../com/ionspin/kotlin/crypto/hash/Hash.kt | 0 .../kotlin/crypto/hash/blake2b/Blake2b.kt | 13 + .../ionspin/kotlin/crypto/hash/sha/Sha256.kt | 12 + .../ionspin/kotlin/crypto/hash/sha/Sha512.kt | 12 + .../keyderivation/KeyDerivationFunction.kt | 0 .../com/ionspin/kotlin/crypto/ReadmeTest.kt | 159 ++ .../com/ionspin/kotlin/crypto/SRNGTest.kt | 37 + .../kotlin/crypto/hash/argon/Argon2KATTest.kt | 158 ++ .../crypto/hash/argon/Argon2MatrixTest.kt | 142 ++ .../kotlin/crypto/hash/argon/Argon2Test.kt | 403 +++++ .../kotlin/crypto/hash/blake2b/Blake2BTest.kt | 293 +++ .../hash/blake2b/Blake2bInstanceTest.kt | 92 + .../hash/blake2b/Blake2bKnowAnswerTests.kt | 1602 +++++++++++++++++ .../kotlin/crypto/hash/sha/Sha256Test.kt | 80 + .../crypto/hash/sha/Sha256UpdateableTest.kt | 100 + .../kotlin/crypto/hash/sha/Sha512Test.kt | 71 + .../crypto/hash/sha/Sha512UpdateableTest.kt | 89 + .../parallelization/CoroutinesDebugTest.kt | 37 + .../kotlin/crypto/symmetric/AesCbcTest.kt | 108 ++ .../kotlin/crypto/symmetric/AesCtrTest.kt | 105 ++ .../kotlin/crypto/symmetric/AesTest.kt | 269 +++ .../ionspin/kotlin/crypto/util/TestUtil.kt | 26 + .../ionspin/kotlin/crypto/util/UtilTest.kt | 109 ++ multiplatform-crypto/build.gradle.kts | 1 + .../ionspin/kotlin/crypto/CryptoProvider.kt | 14 + .../blake2b/{Blake2b.kt => Blake2bPure.kt} | 9 +- .../hash/sha/{Sha256.kt => Sha256Pure.kt} | 5 +- .../hash/sha/{Sha512.kt => Sha512Pure.kt} | 5 +- .../crypto/keyderivation/argon2/Argon2.kt | 400 +--- .../crypto/keyderivation/argon2/Argon2Pure.kt | 405 +++++ .../keyderivation/argon2/Argon2Utils.kt | 12 +- .../crypto/parallelization/Coroutines14.kt | 4 - .../symmetric/{AesCbc.kt => AesCbcPure.kt} | 25 +- .../symmetric/{AesCtr.kt => AesCtrPure.kt} | 23 +- .../crypto/symmetric/{Aes.kt => AesPure.kt} | 6 +- .../com/ionspin/kotlin/crypto/ReadmeTest.kt | 26 +- .../kotlin/crypto/hash/argon/Argon2KATTest.kt | 8 +- .../kotlin/crypto/hash/blake2b/Blake2BTest.kt | 14 +- .../hash/blake2b/Blake2bInstanceTest.kt | 6 +- .../hash/blake2b/Blake2bKnowAnswerTests.kt | 4 +- .../kotlin/crypto/hash/sha/Sha256Test.kt | 8 +- .../crypto/hash/sha/Sha256UpdateableTest.kt | 10 +- .../kotlin/crypto/hash/sha/Sha512Test.kt | 6 +- .../crypto/hash/sha/Sha512UpdateableTest.kt | 8 +- .../kotlin/crypto/symmetric/AesCbcTest.kt | 11 +- .../kotlin/crypto/symmetric/AesCtrTest.kt | 10 +- .../kotlin/crypto/symmetric/AesTest.kt | 38 +- .../ionspin/kotlin/crypto/sample/Runner.kt | 4 +- settings.gradle.kts | 1 + 52 files changed, 5088 insertions(+), 526 deletions(-) create mode 100644 multiplatform-crypto-api/build.gradle.kts create mode 100644 multiplatform-crypto-api/package-lock.json create mode 100644 multiplatform-crypto-api/package.json rename {multiplatform-crypto => multiplatform-crypto-api}/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt (100%) create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt rename {multiplatform-crypto => multiplatform-crypto-api}/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/KeyDerivationFunction.kt (100%) create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/SRNGTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2MatrixTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/parallelization/CoroutinesDebugTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/TestUtil.kt create mode 100644 multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/UtilTest.kt create mode 100644 multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/{Blake2b.kt => Blake2bPure.kt} (97%) rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/{Sha256.kt => Sha256Pure.kt} (99%) rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/{Sha512.kt => Sha512Pure.kt} (99%) create mode 100644 multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/{AesCbc.kt => AesCbcPure.kt} (90%) rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/{AesCtr.kt => AesCtrPure.kt} (90%) rename multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/{Aes.kt => AesPure.kt} (98%) diff --git a/multiplatform-crypto-api/build.gradle.kts b/multiplatform-crypto-api/build.gradle.kts new file mode 100644 index 0000000..127db3d --- /dev/null +++ b/multiplatform-crypto-api/build.gradle.kts @@ -0,0 +1,418 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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. + * + */ + +@file:Suppress("UnstableApiUsage") + +import org.gradle.api.tasks.testing.logging.TestLogging +import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest +import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest +import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile + +plugins { + kotlin(PluginsDeps.multiplatform) + id (PluginsDeps.mavenPublish) + id (PluginsDeps.signing) + id (PluginsDeps.dokka) version Versions.dokkaPlugin +} + +repositories { + mavenCentral() + jcenter() + +} +group = "com.ionspin.kotlin" +version = "0.0.4-SNAPSHOT" + +val ideaActive = System.getProperty("idea.active") == "true" + +fun getHostOsName(): String { + val target = System.getProperty("os.name") + if (target == "Linux") return "linux" + if (target.startsWith("Windows")) return "windows" + if (target.startsWith("Mac")) return "macos" + return "unknown" +} + +kotlin { + val hostOsName = getHostOsName() + if (ideaActive) { + when(hostOsName) { + "linux" -> linuxX64("native") + "macos" -> macosX64("native") + "windows" -> mingwX64("native") + } + } + if (hostOsName == "linux") { + jvm() + js { + compilations { + this.forEach { + it.compileKotlinTask.kotlinOptions.sourceMap = true + it.compileKotlinTask.kotlinOptions.moduleKind = "commonjs" + it.compileKotlinTask.kotlinOptions.metaInfo = true + + if (it.name == "main") { + it.compileKotlinTask.kotlinOptions.main = "call" + } + println("Compilation name ${it.name} set") + println("Destination dir ${it.compileKotlinTask.destinationDir}") + } + } + //Until I figure out how to run headless chrome on travis +// browser { +// +// testTask { +// useKarma { +// useChrome() +// } +// } +// } + nodejs { + testTask { + useMocha() { + timeout = "10s" + } + } + } + + } + linuxX64("linux") { + binaries { + staticLib { + optimized = true + } + } + } + //Not supported in coroutines at the moment +// linuxArm32Hfp() { +// binaries { +// staticLib { +// } +// } +// } + //Not supported in coroutines at the moment +// linuxArm64() { +// binaries { +// staticLib { +// } +// } +// } + + } + + if (hostOsName == "macos") { + iosX64("ios") { + binaries { + framework { + optimized = true + } + } + } + iosArm64("ios64Arm") { + binaries { + framework { + optimized = true + } + } + } + + iosArm32("ios32Arm") { + binaries { + framework { + optimized = true + } + } + } + macosX64() { + binaries { + framework { + optimized = true + } + } + } + } + if (hostOsName == "windows") { + + mingwX64() { + binaries { + staticLib { + optimized = true + } + } + } + } +// No coroutines support for mingwX86 +// mingwX86() { +// binaries { +// staticLib { +// +// } +// } +// } + + + println(targets.names) + + sourceSets { + val commonMain by getting { + dependencies { + implementation(kotlin(Deps.Common.stdLib)) + implementation(kotlin(Deps.Common.test)) + implementation(Deps.Common.coroutines) + implementation(Deps.Common.kotlinBigNum) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin(Deps.Common.test)) + implementation(kotlin(Deps.Common.testAnnotation)) + } + } + + val nativeMain = if (ideaActive) { + val nativeMain by getting { + dependsOn(commonMain) + dependencies { + implementation(Deps.Native.coroutines) + } + } + nativeMain + } else { + val nativeMain by creating { + dependsOn(commonMain) + dependencies { + implementation(Deps.Native.coroutines) + } + } + nativeMain + } + val nativeTest = if (ideaActive) { + val nativeTest by getting { + dependsOn(commonTest) + dependencies { + implementation(Deps.Native.coroutines) + } + } + nativeTest + } else { + val nativeTest by creating { + dependsOn(commonTest) + dependencies { + implementation(Deps.Native.coroutines) + } + } + nativeTest + } + + if (hostOsName == "linux") { + val jvmMain by getting { + dependencies { + implementation(kotlin(Deps.Jvm.stdLib)) + implementation(kotlin(Deps.Jvm.test)) + implementation(kotlin(Deps.Jvm.testJUnit)) + implementation(Deps.Jvm.coroutinesCore) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin(Deps.Jvm.test)) + implementation(kotlin(Deps.Jvm.testJUnit)) + implementation(Deps.Jvm.coroutinesTest) + implementation(kotlin(Deps.Jvm.reflection)) + } + } + val jsMain by getting { + dependencies { + implementation(kotlin(Deps.Js.stdLib)) + implementation(Deps.Js.coroutines) + } + } + val jsTest by getting { + dependencies { + implementation(Deps.Js.coroutines) + implementation(kotlin(Deps.Js.test)) + } + } + val linuxMain by getting { + dependsOn(nativeMain) + } + val linuxTest by getting { + dependsOn(nativeTest) + } + //Not supported in coroutines at the moment +// val linuxArm32HfpMain by getting { +// dependsOn(nativeMain) +// } +// +// val linuxArm32HfpTest by getting { +// dependsOn(nativeTest) +// } + +// val linuxArm64Main by getting { +// dependsOn(nativeMain) +// } +// +// val linuxArm64Test by getting { +// dependsOn(nativeTest) +// } + + } + + if (hostOsName == "macos") { + + val iosMain by getting { + dependsOn(nativeMain) + } + val iosTest by getting { + dependsOn(nativeTest) + } + + val ios64ArmMain by getting { + dependsOn(nativeMain) + } + val ios64ArmTest by getting { + dependsOn(nativeTest) + } + + val ios32ArmMain by getting { + dependsOn(nativeMain) + } + val ios32ArmTest by getting { + dependsOn(nativeTest) + } + + val macosX64Main by getting { + dependsOn(nativeMain) + } + val macosX64Test by getting { + dependsOn(nativeTest) + } + } + +// Coroutines don't support mingwx86 yet +// val mingwX86Main by getting { +// dependsOn(commonMain) +// dependencies { +// implementation(Deps.Native.coroutines) +// } +// } + +// val mingwX86Test by getting { +// dependsOn(commonTest) +// } +// + if (hostOsName == "windows") { + val mingwX64Main by getting { + dependsOn(commonMain) + dependencies { + implementation(Deps.Native.coroutines) + } + } + + val mingwX64Test by getting { + dependsOn(commonTest) + } + } + + + all { + languageSettings.enableLanguageFeature("InlineClasses") + } + } + + +} + +tasks { + + + create("javadocJar") { + dependsOn(dokka) + archiveClassifier.set("javadoc") + from(dokka.get().outputDirectory) + } + + dokka { + println ("Dokka !") + impliedPlatforms = mutableListOf("Common") + kotlinTasks { + listOf() + } + sourceRoot { + println ("Common !") + path = "/home/ionspin/Projects/Future/kotlin-multiplatform-crypto/crypto/src/commonMain" //TODO remove static path! + platforms = listOf("Common") + } + } + if (getHostOsName() == "linux") { + val compileKotlinJs by getting(AbstractCompile::class) + val compileTestKotlinJs by getting(Kotlin2JsCompile::class) + + val jvmTest by getting(Test::class) { + testLogging { + events("PASSED", "FAILED", "SKIPPED") + } + } + + val linuxTest by getting(KotlinNativeTest::class) { + + testLogging { + events("PASSED", "FAILED", "SKIPPED") + // showStandardStreams = true + } + } + + val jsNodeTest by getting(KotlinJsTest::class) { + testLogging { + events("PASSED", "FAILED", "SKIPPED") + showStandardStreams = true + } + } + +// val legacyjsNodeTest by getting(KotlinJsTest::class) { +// +// testLogging { +// events("PASSED", "FAILED", "SKIPPED") +// showStandardStreams = true +// } +// } + +// val jsIrBrowserTest by getting(KotlinJsTest::class) { +// testLogging { +// events("PASSED", "FAILED", "SKIPPED") +// showStandardStreams = true +// } +// } + } + + if (getHostOsName() == "windows") { + val mingwX64Test by getting(KotlinNativeTest::class) { + + testLogging { + events("PASSED", "FAILED", "SKIPPED") + showStandardStreams = true + } + } + } + +} + + + + + + diff --git a/multiplatform-crypto-api/package-lock.json b/multiplatform-crypto-api/package-lock.json new file mode 100644 index 0000000..19fe87b --- /dev/null +++ b/multiplatform-crypto-api/package-lock.json @@ -0,0 +1,201 @@ +{ + "name": "kotlin-multiplatform-crypto-js", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "kotlin": { + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/kotlin/-/kotlin-1.3.40.tgz", + "integrity": "sha512-3l718c3QznxsFNUrnsyGworQZrczyzKRhf+Rx/+7XhSS95S/QrCnlUVuEXA1l9iJpfxx4t9Ecc7+jC1JD28aYg==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/multiplatform-crypto-api/package.json b/multiplatform-crypto-api/package.json new file mode 100644 index 0000000..ffadd88 --- /dev/null +++ b/multiplatform-crypto-api/package.json @@ -0,0 +1,15 @@ +{ + "name": "kotlin-multiplatform-crypto-js", + "version": "0.0.1", + "description": "Kotlin Multiplatform Crypto", + "main": "crypto.js", + "author": "Ugljesa Jovanovic", + "license": "Apache 2.0", + "homepage": "", + "dependencies": { + "kotlin": "1.3.40" + }, + "devDependencies": { + "mocha": "5.2.0" + } +} diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt similarity index 100% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt rename to multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt new file mode 100644 index 0000000..e363538 --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt @@ -0,0 +1,13 @@ +package com.ionspin.kotlin.crypto.hash.blake2b + +import com.ionspin.kotlin.crypto.hash.StatelessHash +import com.ionspin.kotlin.crypto.hash.UpdatableHash + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 24-May-2020 + */ +interface Blake2b : UpdatableHash +interface Blake2bStatelessInterface : StatelessHash + diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt new file mode 100644 index 0000000..9557559 --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt @@ -0,0 +1,12 @@ +package com.ionspin.kotlin.crypto.hash.sha + +import com.ionspin.kotlin.crypto.hash.StatelessHash +import com.ionspin.kotlin.crypto.hash.UpdatableHash + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 24-May-2020 + */ +interface Sha256 : UpdatableHash +interface StatelessSha256 : StatelessHash \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt new file mode 100644 index 0000000..c49bd28 --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt @@ -0,0 +1,12 @@ +package com.ionspin.kotlin.crypto.hash.sha + +import com.ionspin.kotlin.crypto.hash.StatelessHash +import com.ionspin.kotlin.crypto.hash.UpdatableHash + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 24-May-2020 + */ +interface Sha512 : UpdatableHash +interface StatelessSha512 : StatelessHash \ No newline at end of file diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/KeyDerivationFunction.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/KeyDerivationFunction.kt similarity index 100% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/KeyDerivationFunction.kt rename to multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/KeyDerivationFunction.kt diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt new file mode 100644 index 0000000..968269a --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt @@ -0,0 +1,159 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto + +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b +import com.ionspin.kotlin.crypto.hash.sha.Sha256 +import com.ionspin.kotlin.crypto.hash.sha.Sha512 +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 +import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType +import com.ionspin.kotlin.crypto.util.testBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 20-Jul-2019 + */ +@ExperimentalUnsignedTypes +@ExperimentalStdlibApi +class ReadmeTest { + + @Test + fun blake2bObjectExample() { + val input = "abc" + val result = Blake2b.digest(input) + //@formatter:off + val expectedResult = ubyteArrayOf( + 0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U, + 0x4CU,0x21U,0x2FU,0x14U,0x68U,0x5AU,0xC4U,0xB7U,0x4BU,0x12U,0xBBU,0x6FU,0xDBU,0xFFU,0xA2U,0xD1U, + 0x7DU,0x87U,0xC5U,0x39U,0x2AU,0xABU,0x79U,0x2DU,0xC2U,0x52U,0xD5U,0xDEU,0x45U,0x33U,0xCCU,0x95U, + 0x18U,0xD3U,0x8AU,0xA8U,0xDBU,0xF1U,0x92U,0x5AU,0xB9U,0x23U,0x86U,0xEDU,0xD4U,0x00U,0x99U,0x23U + ) + //@formatter:on + + assertTrue { + result.contentEquals(expectedResult) + } + } + + @Test + fun blake2bInstanceExample() { + val test = "abc" + val key = "key" + val blake2b = Blake2b(key) + blake2b.update(test) + val result = blake2b.digest() + + assertTrue { + result.isNotEmpty() + } + val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" + + "6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1") + .chunked(2).map { it.toUByte(16) }.toUByteArray() + + assertTrue { + result.contentEquals(expectedResult) + } + } + + @ExperimentalStdlibApi + @Test + fun sha256Example() { + val input = "abc" + val result = Sha256.digest(inputString = input) + val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalStdlibApi + @Test + fun sha512Example() { + val input = "abc" + val result = Sha512.digest(inputMessage = input.encodeToByteArray().map { it.toUByte() }.toUByteArray()) + println(result.map { it.toString(16) }) + val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalStdlibApi + @Test + fun sha256UpdatableExample() { + val sha256 = Sha256() + sha256.update("abc") + val result = sha256.digest() + val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun sha512UpdatableExample() { + val sha512 = Sha512() + sha512.update("abc") + val result = sha512.digest() + val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalTime + @Test + fun argon2StringExample() = testBlocking { + val argon2Instance = Argon2( + password = "Password", + salt = "RandomSalt", + parallelism = 1, + tagLength = 64U, + requestedMemorySize = 4096U, + numberOfIterations = 2, + key = "", + associatedData = "", + argonType = ArgonType.Argon2id + ) + val time = measureTime { + val tag = argon2Instance.derive() + val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") + val expectedTagString = "c19db7e22d1480702b943872c863baf8c43b53d0c3e2c782cd07bfc613eda159233bd821a945c239c5085c70257f7c93d8a809f81c4af367f4ad8f0443a8fc47" + println("Tag: ${tagString}") + assertEquals(tagString, expectedTagString) + } + println("Time $time") + + } + + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/SRNGTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/SRNGTest.kt new file mode 100644 index 0000000..dba842a --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/SRNGTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-Sep-2019 + */ +class SRNGTest { + @Test + fun testSrng() { + //Just a sanity test, need to add better srng tests. + val randomBytes1 = SRNG.getRandomBytes(10) + val randomBytes2 = SRNG.getRandomBytes(10) + randomBytes1.forEach { println("RB1: $it")} + randomBytes2.forEach { println("RB2: $it")} + assertTrue { !randomBytes1.contentEquals(randomBytes2) } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt new file mode 100644 index 0000000..1c08fcc --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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. + */ + +@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE") + +package com.ionspin.kotlin.crypto.hash.argon + +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 +import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType +import com.ionspin.kotlin.crypto.util.hexColumsPrint +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Known Answer.. TestTest + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 10-May-2020 + */ +@ExperimentalStdlibApi +class Argon2KATTest { + + @Test + fun argon2dKATTest() { + val expected : UByteArray = ubyteArrayOf( + 0x51U, 0x2BU, 0x39U, 0x1BU, 0x6FU, 0x11U, 0x62U, 0x97U, + 0x53U, 0x71U, 0xD3U, 0x09U, 0x19U, 0x73U, 0x42U, 0x94U, + 0xF8U, 0x68U, 0xE3U, 0xBEU, 0x39U, 0x84U, 0xF3U, 0xC1U, + 0xA1U, 0x3AU, 0x4DU, 0xB9U, 0xFAU, 0xBEU, 0x4AU, 0xCBU + ) + + + val memory = 32U //KiB + val iterations = 3 + val parallelism = 4U + val tagLength = 32U + val password: UByteArray = ubyteArrayOf( + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U + ) + val salt: UByteArray = ubyteArrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) + val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) + val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) + + val digest = Argon2( + password, + salt, + parallelism.toInt(), + tagLength, + memory, + iterations, + secret, + associatedData, + ArgonType.Argon2d + ) + val result = digest.derive() + result.hexColumsPrint(8) + assertTrue { expected.contentEquals(result) } + + } + + @Test + fun argon2iKATTest() { + val expected : UByteArray = ubyteArrayOf( + 0xc8U, 0x14U, 0xd9U, 0xd1U, 0xdcU, 0x7fU, 0x37U, 0xaaU, + 0x13U, 0xf0U, 0xd7U, 0x7fU, 0x24U, 0x94U, 0xbdU, 0xa1U, + 0xc8U, 0xdeU, 0x6bU, 0x01U, 0x6dU, 0xd3U, 0x88U, 0xd2U, + 0x99U, 0x52U, 0xa4U, 0xc4U, 0x67U, 0x2bU, 0x6cU, 0xe8U + ) + + + val memory = 32U //KiB + val iterations = 3 + val parallelism = 4U + val tagLength = 32U + val password: UByteArray = ubyteArrayOf( + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U + ) + val salt: UByteArray = ubyteArrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) + val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) + val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) + + val digest = Argon2( + password, + salt, + parallelism.toInt(), + tagLength, + memory, + iterations, + secret, + associatedData, + ArgonType.Argon2i + ) + val result = digest.derive() + result.hexColumsPrint(8) + assertTrue { expected.contentEquals(result) } + + } + + @Test + fun argon2idKATTest() { + val expected : UByteArray = ubyteArrayOf( + 0x0dU, 0x64U, 0x0dU, 0xf5U, 0x8dU, 0x78U, 0x76U, 0x6cU, + 0x08U, 0xc0U, 0x37U, 0xa3U, 0x4aU, 0x8bU, 0x53U, 0xc9U, + 0xd0U, 0x1eU, 0xf0U, 0x45U, 0x2dU, 0x75U, 0xb6U, 0x5eU, + 0xb5U, 0x25U, 0x20U, 0xe9U, 0x6bU, 0x01U, 0xe6U, 0x59U + ) + + + val memory = 32U //KiB + val iterations = 3 + val parallelism = 4U + val tagLength = 32U + val password: UByteArray = ubyteArrayOf( + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U + ) + val salt: UByteArray = ubyteArrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) + val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) + val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) + + val digest = Argon2( + password, + salt, + parallelism.toInt(), + tagLength, + memory, + iterations, + secret, + associatedData, + ArgonType.Argon2id + ) + val result = digest.derive() + result.hexColumsPrint(8) + assertTrue { expected.contentEquals(result) } + + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2MatrixTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2MatrixTest.kt new file mode 100644 index 0000000..ad69c98 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2MatrixTest.kt @@ -0,0 +1,142 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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. + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") + +package com.ionspin.kotlin.crypto.hash.argon + +import com.ionspin.kotlin.crypto.keyderivation.argon2.* +import com.ionspin.kotlin.crypto.util.arrayChunked +import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong +import kotlin.random.Random +import kotlin.random.nextUBytes +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-May-2020 + */ +class Argon2MatrixTest { + val zeroesBlock = UByteArray(1024) { 0U } + val onesBlock = UByteArray(1024) { 1U } + val twosBlock = UByteArray(1024) { 2U } + val threesBlock = UByteArray(1024) { 3U } + + val random = Random(1) + val randomBlockArray = random.nextUBytes(1024) + + + @Test + fun indexAccessTest() { + val argon2Matrix = ArgonMatrix(2, 2) + (zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage) + println(argon2Matrix[0, 0, 0]) + println(argon2Matrix[0, 1, 0]) + println(argon2Matrix[1, 0, 0]) + println(argon2Matrix[1, 1, 0]) +// argon2Matrix.storage.hexColumsPrint(1024) + var expectedByteValue = 0U.toUByte() + for (lane in 0 until 2) { + for (column in 0 until 2) { + for (blockPosition in 0 until 1024) { + assertTrue { + argon2Matrix[lane, column, blockPosition] == expectedByteValue + } + } + expectedByteValue++ + } + } + assertTrue { + argon2Matrix[0, 0, 0] == 0U.toUByte() && + argon2Matrix[0, 1, 0] == 1U.toUByte() && + argon2Matrix[1, 0, 0] == 2U.toUByte() && + argon2Matrix[1, 1, 0] == 3U.toUByte() + + } + } + + @Test + fun blockRetrievalTest() { + val argon2Matrix = ArgonMatrix(2, 2) + (zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage) + assertTrue { + zeroesBlock.contentEquals(argon2Matrix.getBlockAt(0, 0)) && + onesBlock.contentEquals(argon2Matrix.getBlockAt(0, 1)) && + twosBlock.contentEquals(argon2Matrix.getBlockAt(1, 0)) && + threesBlock.contentEquals(argon2Matrix.getBlockAt(1, 1)) + } + } + + @Test + fun blockColumnToUlongTest() { + val randomBlock = ArgonBlock(randomBlockArray) + for (columnIndex in 0 until 8) { + val startOfRow = (columnIndex * 8 * 16) + val endOfRow = startOfRow + (8 * 16) + val rowToMix = randomBlockArray.copyOfRange(startOfRow, endOfRow) + val expected = rowToMix.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toULongArray() + + val result = randomBlock.getBlockPointer().getRowOfULongsForMixing(columnIndex) + + assertTrue { expected.contentEquals(result) } + } + } + + @Test + fun blockRowToULongTest() { + val randomBlock = ArgonBlock(randomBlockArray) + for (rowIndex in 0 until 8) { + val columnToMix = Argon2Utils.extractColumnFromGBlock(randomBlockArray, rowIndex) + val expected = columnToMix.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toULongArray() + val result = randomBlock.getBlockPointer().getColumnOfULongsForMixing(rowIndex) + + assertTrue { expected.contentEquals(result) } + } + } + + @Test + fun blockSetMixedRowTest() { + val randomBlock = ArgonBlock(randomBlockArray) + val targetBlockArray = zeroesBlock.copyOf() + val targetBlock = ArgonBlock(targetBlockArray) + for (rowIndex in 0 until 8) { + val extracted = randomBlock.getBlockPointer().getRowOfULongsForMixing(rowIndex) + targetBlock.getBlockPointer().setRowFromMixedULongs(rowIndex, extracted) + } + + assertTrue { + randomBlockArray.contentEquals(targetBlock.storage) + } + } + + @Test + fun blockSetMixedColumnTest() { + val randomBlock = ArgonBlock(randomBlockArray) + val targetBlockArray = zeroesBlock.copyOf() + val targetBlock = ArgonBlock(targetBlockArray) + for (columnIndex in 0 until 8) { + val extracted = randomBlock.getBlockPointer().getColumnOfULongsForMixing(columnIndex) + targetBlock.getBlockPointer().setColumnFromMixedULongs(columnIndex, extracted) + } + + assertTrue { + randomBlockArray.contentEquals(targetBlock.storage) + } + } + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt new file mode 100644 index 0000000..f513b7d --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt @@ -0,0 +1,403 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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. + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") + +package com.ionspin.kotlin.crypto.hash.argon + +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils +import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonBlock +import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong +import kotlin.random.Random +import kotlin.random.nextUBytes +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-May-2020 + */ +class Argon2Test { + val seededRandom = Random(1L) + val randomBlockAsArray = seededRandom.nextUBytes(1024) + val randomBlockAsArray2 = seededRandom.nextUBytes(1024) + val randomBlockAsArray3 = seededRandom.nextUBytes(1024) + + @Test + fun mixRoundTest() { + val input = ubyteArrayOf( + 0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, + 0x08U, 0x09U, 0x0aU, 0x0bU, 0x0cU, 0x0dU, 0x0eU, 0x0fU, + 0x10U, 0x11U, 0x12U, 0x13U, 0x14U, 0x15U, 0x16U, 0x17U, + 0x18U, 0x19U, 0x1aU, 0x1bU, 0x1cU, 0x1dU, 0x1eU, 0x1fU, + 0x20U, 0x21U, 0x22U, 0x23U, 0x24U, 0x25U, 0x26U, 0x27U, + 0x28U, 0x29U, 0x2aU, 0x2bU, 0x2cU, 0x2dU, 0x2eU, 0x2fU, + 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, + 0x38U, 0x39U, 0x3aU, 0x3bU, 0x3cU, 0x3dU, 0x3eU, 0x3fU, + 0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, + 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, + 0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, + 0x58U, 0x59U, 0x5aU, 0x5bU, 0x5cU, 0x5dU, 0x5eU, 0x5fU, + 0x60U, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, 0x67U, + 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, + 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, 0x77U, + 0x78U, 0x79U, 0x7aU, 0x7bU, 0x7cU, 0x7dU, 0x7eU, 0x7fU + ) + + val expected = arrayOf( + 16438755999881694465U, + 2631578750119870528U, + 8840261388583117524U, + 13886387434724287670U, + 14214935523062117944U, + 6768869593113706780U, + 12323449447979969623U, + 7512951229622659062U, + 9291745133539598579U, + 11220895723773995914U, + 2509429320847842905U, + 5637172405908834370U, + 8517838221434905893U, + 14206719563334097702U, + 6500029010075826286U, + 16957672821843227543U + ) + val preparedInput = input.chunked(8).map { it.toTypedArray().fromLittleEndianArrayToULong() }.toULongArray() + val result = Argon2Utils.inplaceMixRound(preparedInput) + assertTrue { + expected.contentEquals(result.toTypedArray()) + } + + } + + @Test + fun testExtractColumnFromGBlock() { + val expected = ubyteArrayOf( + 0x1AU, 0x2AU, 0xC5U, 0x23U, 0xB0U, 0x05U, 0xB1U, 0xA4U, + 0x61U, 0x48U, 0x93U, 0xE0U, 0x6DU, 0x33U, 0xB6U, 0xA0U, + 0x63U, 0x13U, 0xFFU, 0xEBU, 0x56U, 0x48U, 0xE7U, 0xD0U, + 0x47U, 0x58U, 0x8EU, 0xD7U, 0xDEU, 0x01U, 0xCFU, 0x96U, + 0xB4U, 0xE0U, 0x2AU, 0xF0U, 0x16U, 0x33U, 0x54U, 0xA9U, + 0xF3U, 0xC3U, 0x98U, 0x2CU, 0xB7U, 0xECU, 0x1AU, 0x66U, + 0xE0U, 0x6CU, 0xA5U, 0x66U, 0x73U, 0xE8U, 0x8AU, 0xF7U, + 0x50U, 0x96U, 0xB8U, 0x16U, 0x47U, 0x41U, 0xA6U, 0x4CU, + 0xAEU, 0x89U, 0xBAU, 0x5DU, 0x3CU, 0x49U, 0x33U, 0x23U, + 0xD3U, 0xFBU, 0xD4U, 0x04U, 0x11U, 0x8FU, 0x98U, 0x10U, + 0xDCU, 0xB7U, 0x06U, 0xE0U, 0x58U, 0xCFU, 0x48U, 0xE3U, + 0x1FU, 0x33U, 0xE6U, 0x66U, 0x20U, 0xD2U, 0x34U, 0x43U, + 0x62U, 0xA0U, 0x02U, 0x7FU, 0xE9U, 0x36U, 0xB3U, 0xB5U, + 0x6BU, 0x07U, 0x8CU, 0xA7U, 0xB1U, 0x11U, 0x28U, 0x6FU, + 0x6BU, 0xD0U, 0x09U, 0x4FU, 0xACU, 0x48U, 0x18U, 0xDCU, + 0x70U, 0xB6U, 0xD6U, 0x27U, 0x69U, 0x50U, 0x97U, 0x87U, + ) + val extracted = Argon2Utils.extractColumnFromGBlock(randomBlockAsArray, 0) + assertTrue { + expected.contentEquals(extracted) + } + + } + + @Test + fun testCompressionFunctionGWithoutXor() { + val expectedWithoutXor = ubyteArrayOf( + 0x94U, 0xE8U, 0x52U, 0x79U, 0xA7U, 0xE5U, 0x66U, 0xAAU, + 0xD7U, 0xE1U, 0x8EU, 0x72U, 0x42U, 0xA2U, 0xE1U, 0x50U, + 0x5FU, 0x77U, 0x7DU, 0xCDU, 0xE1U, 0xEFU, 0xAAU, 0xF5U, + 0x29U, 0x94U, 0x29U, 0x17U, 0x9DU, 0x79U, 0xA5U, 0x67U, + 0xD7U, 0x6CU, 0x11U, 0x18U, 0x6FU, 0xE0U, 0xA4U, 0x26U, + 0xCCU, 0xF4U, 0xFDU, 0xD1U, 0xE0U, 0x42U, 0xC1U, 0x6AU, + 0x33U, 0x99U, 0xC4U, 0x27U, 0x33U, 0x67U, 0xDDU, 0xC3U, + 0x57U, 0x81U, 0xF5U, 0xCDU, 0x05U, 0x22U, 0x2DU, 0x5FU, + 0x71U, 0x83U, 0xA9U, 0x54U, 0x1BU, 0x09U, 0x40U, 0x68U, + 0x6DU, 0x78U, 0x0FU, 0x23U, 0xE2U, 0x90U, 0xC1U, 0x2DU, + 0xBFU, 0x44U, 0x26U, 0xADU, 0x8BU, 0x77U, 0x0EU, 0xFBU, + 0x9AU, 0x95U, 0x7AU, 0x8DU, 0xEAU, 0xCAU, 0xA2U, 0x1BU, + 0xBDU, 0xC0U, 0x90U, 0x85U, 0x37U, 0xD9U, 0xF3U, 0x94U, + 0x59U, 0x9EU, 0xB4U, 0xC4U, 0xBCU, 0xC1U, 0x47U, 0x31U, + 0x66U, 0xE4U, 0x66U, 0x0EU, 0x86U, 0x11U, 0x4AU, 0x4CU, + 0x36U, 0xA1U, 0x1CU, 0xDEU, 0xE9U, 0xA4U, 0x03U, 0x1FU, + 0x9CU, 0x7AU, 0x1BU, 0x7AU, 0x8FU, 0x17U, 0xA3U, 0xD4U, + 0x5BU, 0x23U, 0x8AU, 0x55U, 0x53U, 0x86U, 0x64U, 0xEDU, + 0x24U, 0x97U, 0xFAU, 0x70U, 0xD4U, 0xF1U, 0x9AU, 0x10U, + 0xBCU, 0x24U, 0x03U, 0xACU, 0x24U, 0x91U, 0x83U, 0xFBU, + 0x66U, 0x02U, 0xC2U, 0x37U, 0xBEU, 0x63U, 0xCEU, 0x59U, + 0xEAU, 0x02U, 0xAFU, 0x6CU, 0x8DU, 0x14U, 0xECU, 0xFDU, + 0x5BU, 0x0AU, 0x0EU, 0xB6U, 0x51U, 0x2FU, 0x75U, 0xF1U, + 0xA9U, 0x88U, 0xD1U, 0x05U, 0x60U, 0xE6U, 0xEDU, 0x17U, + 0x4AU, 0x03U, 0x1FU, 0xF7U, 0x71U, 0x86U, 0x26U, 0x18U, + 0x7EU, 0xB3U, 0x31U, 0x78U, 0xD8U, 0xB7U, 0x2CU, 0xD0U, + 0x6DU, 0xB5U, 0xAEU, 0xDFU, 0x85U, 0xC6U, 0x87U, 0x9FU, + 0x18U, 0x85U, 0x1BU, 0x22U, 0x19U, 0x15U, 0x00U, 0xF8U, + 0x03U, 0xF7U, 0x48U, 0xA4U, 0xFCU, 0xE3U, 0xE4U, 0x93U, + 0x02U, 0x57U, 0x71U, 0xBCU, 0xF6U, 0x2DU, 0x45U, 0xBEU, + 0x87U, 0xC1U, 0x21U, 0x11U, 0x77U, 0x23U, 0x78U, 0xFCU, + 0x56U, 0xBFU, 0x92U, 0x49U, 0xA1U, 0x51U, 0xE9U, 0x22U, + 0x24U, 0x10U, 0x30U, 0x2EU, 0xE1U, 0xC1U, 0xF7U, 0x96U, + 0xB0U, 0x27U, 0xF7U, 0x6CU, 0x65U, 0x0CU, 0x1BU, 0xE1U, + 0xB2U, 0x12U, 0xD3U, 0xBCU, 0x8BU, 0xEDU, 0x9DU, 0x14U, + 0x81U, 0x82U, 0xB3U, 0x5BU, 0x70U, 0x2CU, 0x65U, 0x54U, + 0xF5U, 0x1FU, 0x1CU, 0x37U, 0xD2U, 0xD1U, 0x89U, 0x35U, + 0x57U, 0x52U, 0xDDU, 0xA7U, 0x02U, 0x81U, 0x14U, 0xF7U, + 0x6CU, 0x4CU, 0xB9U, 0x02U, 0x96U, 0x72U, 0xD2U, 0xFEU, + 0x30U, 0x66U, 0x8CU, 0x16U, 0x50U, 0xB1U, 0x51U, 0xE9U, + 0x48U, 0x48U, 0x83U, 0xA6U, 0x5CU, 0xF9U, 0x98U, 0x59U, + 0xBAU, 0x2DU, 0xE5U, 0x73U, 0xADU, 0xD1U, 0x6AU, 0x7AU, + 0x1FU, 0x6EU, 0xD8U, 0xC9U, 0xEDU, 0x00U, 0x9AU, 0xB1U, + 0x34U, 0x08U, 0x0AU, 0x81U, 0x3EU, 0xCCU, 0x44U, 0xB7U, + 0xD6U, 0xFEU, 0x0FU, 0x5CU, 0x19U, 0xD8U, 0x8FU, 0xEDU, + 0x46U, 0x88U, 0xF5U, 0x5DU, 0x6BU, 0xDAU, 0x4DU, 0x02U, + 0xA9U, 0xFCU, 0x67U, 0xBEU, 0x0CU, 0x09U, 0x38U, 0x98U, + 0x79U, 0x52U, 0x7DU, 0xA6U, 0x24U, 0xA8U, 0x3BU, 0xB1U, + 0xB2U, 0x52U, 0xC8U, 0x83U, 0x6CU, 0x02U, 0xD8U, 0xBDU, + 0x7FU, 0x98U, 0xCCU, 0x65U, 0x01U, 0x90U, 0x6EU, 0x60U, + 0xF8U, 0xB8U, 0x94U, 0xABU, 0x7BU, 0xA9U, 0x5FU, 0xE9U, + 0xDAU, 0xCCU, 0x94U, 0x00U, 0xEDU, 0x8FU, 0x03U, 0xA3U, + 0xCFU, 0xB3U, 0x14U, 0x38U, 0x94U, 0x91U, 0xF3U, 0x61U, + 0xEBU, 0x04U, 0xDEU, 0x9DU, 0x9DU, 0x05U, 0x98U, 0xF3U, + 0x71U, 0xB1U, 0xB3U, 0xB1U, 0x1DU, 0xA3U, 0x55U, 0x47U, + 0xF4U, 0xA3U, 0xF8U, 0x7AU, 0x11U, 0xBBU, 0x0DU, 0x9CU, + 0xB1U, 0x57U, 0xAAU, 0xC2U, 0x3CU, 0x0BU, 0xBEU, 0x77U, + 0xBCU, 0x25U, 0x03U, 0x8BU, 0x7FU, 0x81U, 0xA5U, 0x7EU, + 0xA9U, 0xB4U, 0x3FU, 0x5AU, 0x11U, 0x54U, 0x75U, 0x7DU, + 0x45U, 0x20U, 0x90U, 0x46U, 0x98U, 0x70U, 0xF5U, 0x5BU, + 0xA5U, 0x9DU, 0x46U, 0x63U, 0x62U, 0x3DU, 0x04U, 0x2FU, + 0xB9U, 0x67U, 0x31U, 0xC5U, 0x92U, 0x48U, 0x18U, 0x0FU, + 0xDCU, 0x52U, 0x78U, 0xCBU, 0x7CU, 0x86U, 0x58U, 0xDBU, + 0x0BU, 0x06U, 0xF2U, 0x93U, 0x83U, 0x26U, 0x99U, 0x5DU, + 0xBDU, 0xFBU, 0x87U, 0xC9U, 0x55U, 0x41U, 0xACU, 0x5FU, + 0xA3U, 0xF9U, 0x71U, 0x53U, 0x93U, 0x53U, 0xC5U, 0xE4U, + 0x3FU, 0x78U, 0x31U, 0x8FU, 0x7CU, 0x0BU, 0x77U, 0x84U, + 0x43U, 0xACU, 0x4DU, 0xD1U, 0xC9U, 0x9BU, 0x4BU, 0x60U, + 0x00U, 0xFEU, 0x41U, 0x10U, 0xEFU, 0xDFU, 0x80U, 0x95U, + 0x03U, 0x23U, 0xBEU, 0xF6U, 0x6BU, 0x60U, 0xE5U, 0x6FU, + 0x9EU, 0x6BU, 0x7CU, 0x24U, 0xA7U, 0xC1U, 0xF8U, 0xBBU, + 0x60U, 0x55U, 0x57U, 0x18U, 0x58U, 0x32U, 0x97U, 0xE8U, + 0x53U, 0x71U, 0x05U, 0x59U, 0xE3U, 0x94U, 0xB1U, 0x60U, + 0x8AU, 0x40U, 0x24U, 0xF6U, 0x29U, 0x49U, 0x65U, 0xADU, + 0x65U, 0xE3U, 0xCEU, 0x9FU, 0x4FU, 0x47U, 0xA0U, 0x07U, + 0x2FU, 0x1CU, 0xA7U, 0x3AU, 0x04U, 0x17U, 0x87U, 0x1BU, + 0x06U, 0xC5U, 0x93U, 0x63U, 0x3FU, 0x18U, 0x3BU, 0x8BU, + 0x3EU, 0xD4U, 0xC0U, 0xC9U, 0x7EU, 0xB6U, 0x32U, 0xD3U, + 0xC3U, 0x8BU, 0x55U, 0x2CU, 0x5BU, 0xB7U, 0xEBU, 0x88U, + 0x14U, 0x63U, 0xB8U, 0x3BU, 0xDBU, 0xFFU, 0x49U, 0x44U, + 0x79U, 0xD2U, 0x82U, 0xD8U, 0xA6U, 0x47U, 0x45U, 0xFBU, + 0xF5U, 0x4BU, 0x5AU, 0x43U, 0x19U, 0xD9U, 0xD5U, 0x52U, + 0x04U, 0x0CU, 0x4BU, 0x74U, 0x87U, 0x0DU, 0x11U, 0x8DU, + 0x51U, 0x9DU, 0x66U, 0x68U, 0x41U, 0xE0U, 0xFCU, 0x92U, + 0x24U, 0x7FU, 0x62U, 0xAFU, 0x8BU, 0x53U, 0xDEU, 0x84U, + 0xF0U, 0xA1U, 0x03U, 0xAAU, 0x17U, 0x6FU, 0xD3U, 0x10U, + 0x57U, 0x25U, 0xC6U, 0xA3U, 0x8FU, 0x1AU, 0xD3U, 0xD7U, + 0x0DU, 0x89U, 0x22U, 0x3CU, 0x17U, 0xC6U, 0xF7U, 0x02U, + 0x0CU, 0xD9U, 0x0FU, 0xABU, 0x27U, 0xA6U, 0xE3U, 0x20U, + 0xF4U, 0xB2U, 0x21U, 0x12U, 0x85U, 0xF5U, 0x98U, 0x45U, + 0x16U, 0x24U, 0xF7U, 0x46U, 0x5DU, 0x1FU, 0x41U, 0x9AU, + 0x0EU, 0x25U, 0x4AU, 0x99U, 0x27U, 0x5CU, 0x0BU, 0xC8U, + 0x33U, 0x99U, 0x65U, 0x3CU, 0xC9U, 0xDBU, 0x78U, 0x6DU, + 0x36U, 0xC6U, 0x37U, 0x35U, 0x2EU, 0x97U, 0x04U, 0x03U, + 0x26U, 0x78U, 0x5AU, 0x5AU, 0xD8U, 0xEAU, 0xF7U, 0xF1U, + 0xF9U, 0x22U, 0x9DU, 0xDEU, 0xB7U, 0x50U, 0xFEU, 0x91U, + 0xD4U, 0x5EU, 0xA1U, 0xC2U, 0x1BU, 0xE4U, 0x3FU, 0x19U, + 0x50U, 0x21U, 0x1FU, 0x38U, 0xA1U, 0x11U, 0xB1U, 0x08U, + 0x7DU, 0xA2U, 0xBBU, 0xE5U, 0xECU, 0x1BU, 0x9FU, 0x51U, + 0x77U, 0x6CU, 0xB9U, 0xA8U, 0xC2U, 0x76U, 0xD4U, 0xCBU, + 0x11U, 0x7DU, 0x4AU, 0x92U, 0xE2U, 0x0AU, 0x96U, 0x9AU, + 0x28U, 0x72U, 0xFFU, 0xAAU, 0xF8U, 0xD5U, 0x64U, 0x8AU, + 0x45U, 0x71U, 0xF3U, 0xB5U, 0xD7U, 0x2AU, 0x3BU, 0x7FU, + 0x5CU, 0xFCU, 0x2DU, 0x89U, 0xBCU, 0x64U, 0x2FU, 0x63U, + 0x87U, 0xE6U, 0x57U, 0xECU, 0x06U, 0xE3U, 0xDDU, 0x15U, + 0xB4U, 0x27U, 0xA8U, 0x6CU, 0x37U, 0x54U, 0xD3U, 0x37U, + 0xCFU, 0x4DU, 0x71U, 0x04U, 0x91U, 0x08U, 0x1AU, 0xC6U, + 0xBDU, 0xEBU, 0x86U, 0xC5U, 0x5AU, 0x63U, 0x19U, 0xD5U, + 0xC5U, 0xCBU, 0x82U, 0xC3U, 0x54U, 0x57U, 0xD8U, 0x6CU, + 0x8FU, 0x9AU, 0xF1U, 0x7BU, 0x08U, 0x61U, 0xFCU, 0x96U, + 0x1AU, 0xCEU, 0x8FU, 0x11U, 0xE2U, 0xDDU, 0x96U, 0xA3U, + 0x57U, 0xD7U, 0x0DU, 0x28U, 0x06U, 0x0AU, 0xC5U, 0x1FU, + 0xBBU, 0xC6U, 0x67U, 0xC8U, 0xB0U, 0xA7U, 0xDAU, 0x00U, + 0xC3U, 0x00U, 0x21U, 0xACU, 0xFFU, 0xE9U, 0x4FU, 0xB7U, + 0x9AU, 0xC9U, 0x77U, 0xC3U, 0x96U, 0x6EU, 0x1CU, 0xC4U, + 0x61U, 0xAEU, 0x6FU, 0x55U, 0x0CU, 0xDAU, 0x68U, 0x48U, + 0x97U, 0xEDU, 0x9CU, 0x90U, 0x17U, 0x2AU, 0x2DU, 0xC9U, + 0x2AU, 0x77U, 0x87U, 0xECU, 0x64U, 0xF5U, 0x78U, 0x99U, + 0xA9U, 0xB9U, 0x11U, 0x05U, 0xE9U, 0x7BU, 0x3BU, 0x49U, + 0xAEU, 0x61U, 0x70U, 0x0BU, 0xBFU, 0xB7U, 0x67U, 0xA8U, + 0x9FU, 0x02U, 0x30U, 0xD3U, 0x0BU, 0x14U, 0xF0U, 0x89U, + 0x95U, 0x87U, 0x5BU, 0x04U, 0xF3U, 0x27U, 0xEFU, 0x91U, + 0x4AU, 0xD4U, 0x7FU, 0x9EU, 0x73U, 0x95U, 0xE5U, 0x48U, + 0x7FU, 0xE4U, 0xF6U, 0x92U, 0x85U, 0x47U, 0xA5U, 0xFEU, + 0x12U, 0xD7U, 0xC4U, 0x9EU, 0xCFU, 0x8AU, 0xC2U, 0xD2U, + 0x10U, 0x94U, 0xE5U, 0x58U, 0xBBU, 0xE0U, 0xEEU, 0xD9U, + 0x6AU, 0x59U, 0xD9U, 0xBCU, 0xD5U, 0xCDU, 0xA0U, 0xBCU, + 0xD7U, 0x96U, 0xAAU, 0x23U, 0xA9U, 0x10U, 0x6CU, 0x7EU, + + ) + + val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() + val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() + val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() + val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false) + assertTrue { + expectedWithoutXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) + } + } + + @Test + fun compressionFunctionGWithXor() { + val expectedWithXor = ubyteArrayOf( + + 0x44U, 0xD8U, 0x76U, 0x1AU, 0xD5U, 0x31U, 0xA5U, 0xEDU, + 0xFAU, 0xABU, 0x43U, 0x60U, 0x21U, 0xB6U, 0x7DU, 0x28U, + 0x65U, 0xF4U, 0xAFU, 0x07U, 0x1DU, 0x01U, 0xB4U, 0x50U, + 0x85U, 0x3DU, 0x03U, 0x4CU, 0x33U, 0x58U, 0x8FU, 0xDCU, + 0x10U, 0xDEU, 0x26U, 0xF4U, 0xEDU, 0x58U, 0xD1U, 0x84U, + 0x7AU, 0x0AU, 0x05U, 0xC7U, 0x6BU, 0xA4U, 0xADU, 0x31U, + 0x18U, 0x5DU, 0x11U, 0x10U, 0x5FU, 0x2FU, 0x5EU, 0x6CU, + 0x3DU, 0x7EU, 0x3BU, 0xA8U, 0x92U, 0x61U, 0x80U, 0x84U, + 0xD1U, 0x45U, 0x83U, 0x85U, 0xE6U, 0x14U, 0x4CU, 0x98U, + 0x30U, 0xC1U, 0xB5U, 0x7FU, 0x50U, 0x56U, 0x71U, 0x43U, + 0xEAU, 0x84U, 0x38U, 0x2AU, 0x42U, 0x95U, 0xF6U, 0x28U, + 0x97U, 0x6BU, 0x86U, 0x6AU, 0x67U, 0x83U, 0xD1U, 0x87U, + 0xA6U, 0x19U, 0x05U, 0x7AU, 0x11U, 0xA1U, 0x6EU, 0x10U, + 0xCFU, 0x51U, 0x6CU, 0xE6U, 0x63U, 0x32U, 0x45U, 0xBCU, + 0x6BU, 0x40U, 0xDBU, 0x8FU, 0x47U, 0x5BU, 0x4BU, 0x36U, + 0x3CU, 0xB4U, 0xC8U, 0xF2U, 0x0AU, 0xE1U, 0xE1U, 0xFEU, + 0x1FU, 0x8BU, 0xE4U, 0x36U, 0x75U, 0xEBU, 0x70U, 0x52U, + 0x1DU, 0xE8U, 0xDEU, 0xD0U, 0xC4U, 0x7CU, 0x9CU, 0x33U, + 0xC7U, 0x42U, 0x69U, 0x85U, 0x3FU, 0x99U, 0x75U, 0x59U, + 0x9BU, 0xBEU, 0x02U, 0xC0U, 0xBEU, 0xC7U, 0x24U, 0xD0U, + 0x66U, 0xD2U, 0x99U, 0xD5U, 0x43U, 0xECU, 0x8FU, 0xA2U, + 0x17U, 0x10U, 0x56U, 0x1DU, 0x23U, 0xBAU, 0x33U, 0xF9U, + 0x9AU, 0xEBU, 0x6BU, 0x0FU, 0x32U, 0x95U, 0x5BU, 0xB5U, + 0x74U, 0x1DU, 0x22U, 0x36U, 0x1FU, 0x49U, 0xD6U, 0xC2U, + 0xC0U, 0xEAU, 0xA1U, 0x07U, 0x73U, 0x9CU, 0x85U, 0x78U, + 0xD6U, 0x63U, 0x98U, 0x44U, 0x7FU, 0x98U, 0x80U, 0x6BU, + 0xC5U, 0x99U, 0x35U, 0xBCU, 0xB3U, 0xAAU, 0x8FU, 0xEBU, + 0x32U, 0x62U, 0xAEU, 0xF7U, 0xAEU, 0x23U, 0x96U, 0xCBU, + 0x58U, 0x84U, 0x50U, 0xA7U, 0x4CU, 0x85U, 0x7BU, 0xE3U, + 0x32U, 0xE4U, 0xFAU, 0x66U, 0x25U, 0x60U, 0x64U, 0xA2U, + 0x6FU, 0xE2U, 0x68U, 0xBDU, 0x61U, 0x5DU, 0x2CU, 0xD3U, + 0x58U, 0xE2U, 0xC5U, 0x8CU, 0x42U, 0xC9U, 0x9CU, 0xECU, + 0x62U, 0xE5U, 0xA9U, 0xC3U, 0x20U, 0x72U, 0x59U, 0x6AU, + 0xF1U, 0xEAU, 0x54U, 0xEAU, 0xE6U, 0x80U, 0x09U, 0x8BU, + 0x55U, 0x6CU, 0xDDU, 0x26U, 0x69U, 0xFDU, 0x25U, 0x97U, + 0xDCU, 0xAFU, 0x1BU, 0x04U, 0x08U, 0xC2U, 0x54U, 0xBAU, + 0xACU, 0xCBU, 0x97U, 0x7AU, 0xDBU, 0x59U, 0x8FU, 0x7DU, + 0x95U, 0xB4U, 0x41U, 0x8AU, 0xC9U, 0xB4U, 0xF3U, 0xC0U, + 0x5BU, 0x75U, 0x4EU, 0xE9U, 0x24U, 0x7FU, 0x8CU, 0xA1U, + 0x05U, 0x6EU, 0x3BU, 0x3EU, 0xBDU, 0x03U, 0xE4U, 0x41U, + 0x26U, 0x58U, 0x09U, 0xC1U, 0xE6U, 0x8EU, 0x22U, 0x59U, + 0x3BU, 0xEEU, 0x21U, 0x5BU, 0x43U, 0x37U, 0x65U, 0xD2U, + 0x13U, 0x6CU, 0xF8U, 0x06U, 0x48U, 0xADU, 0x09U, 0x9AU, + 0xE1U, 0xE5U, 0x0CU, 0x2DU, 0x52U, 0xADU, 0x3BU, 0xC7U, + 0xE7U, 0x78U, 0x7EU, 0xCDU, 0x1EU, 0xE9U, 0x7AU, 0x5DU, + 0x54U, 0x89U, 0x1EU, 0xEFU, 0xA2U, 0x44U, 0xF4U, 0x38U, + 0xE7U, 0xB5U, 0x0FU, 0xC8U, 0x1FU, 0x7EU, 0x9CU, 0x93U, + 0x88U, 0x71U, 0xAEU, 0x19U, 0x0DU, 0x0FU, 0xCFU, 0xF1U, + 0xCFU, 0x67U, 0x94U, 0x0FU, 0x5FU, 0xB2U, 0xC3U, 0x8FU, + 0xE8U, 0xC3U, 0x07U, 0x0EU, 0xECU, 0x99U, 0x36U, 0x57U, + 0x7AU, 0xA6U, 0xA9U, 0x44U, 0x5BU, 0x68U, 0x5AU, 0xB4U, + 0xBFU, 0xA9U, 0xC9U, 0xE5U, 0xC8U, 0x20U, 0x31U, 0xD2U, + 0xE9U, 0x3EU, 0x6FU, 0x09U, 0x8FU, 0x7DU, 0x75U, 0x0EU, + 0x35U, 0xE8U, 0x90U, 0x04U, 0xB8U, 0x4AU, 0x12U, 0xE5U, + 0xC0U, 0xCCU, 0x6AU, 0xB0U, 0x9FU, 0x8FU, 0xAFU, 0x8CU, + 0x83U, 0x13U, 0x43U, 0x8EU, 0x5FU, 0x8AU, 0x1EU, 0xD3U, + 0xF2U, 0x9AU, 0xE5U, 0x95U, 0x6DU, 0xAEU, 0x4DU, 0xDBU, + 0x0CU, 0x06U, 0xDEU, 0x5CU, 0xD0U, 0x68U, 0xFFU, 0x4CU, + 0xECU, 0x82U, 0xC8U, 0xAFU, 0x44U, 0xC0U, 0x3BU, 0x0BU, + 0x89U, 0xADU, 0x32U, 0xAEU, 0xE7U, 0x36U, 0x2AU, 0x05U, + 0x18U, 0x5FU, 0xB9U, 0xBDU, 0x52U, 0x7FU, 0x73U, 0x70U, + 0x5AU, 0x5BU, 0x88U, 0x20U, 0x16U, 0x84U, 0xECU, 0x91U, + 0xF7U, 0xD2U, 0x2FU, 0x6DU, 0x69U, 0x37U, 0xEAU, 0x2BU, + 0x24U, 0xA2U, 0x58U, 0xDAU, 0x01U, 0x32U, 0x91U, 0x94U, + 0x53U, 0x4DU, 0xBDU, 0x28U, 0xEAU, 0x70U, 0x75U, 0x77U, + 0xD7U, 0x5DU, 0xF0U, 0xAAU, 0x5AU, 0x39U, 0xB9U, 0xC7U, + 0xDBU, 0xC0U, 0xCFU, 0x72U, 0x6DU, 0xB0U, 0x04U, 0xBDU, + 0x34U, 0x58U, 0x2AU, 0x6BU, 0x46U, 0xEDU, 0x7DU, 0x1AU, + 0x15U, 0x85U, 0xD3U, 0x14U, 0xC6U, 0xF9U, 0x32U, 0x72U, + 0x9AU, 0xD9U, 0x1AU, 0xBFU, 0xBDU, 0x3CU, 0x45U, 0x46U, + 0x17U, 0x6DU, 0xAEU, 0x1EU, 0x12U, 0xE5U, 0x00U, 0x6DU, + 0xD4U, 0xC0U, 0x71U, 0x8BU, 0xAFU, 0x12U, 0x7BU, 0x1EU, + 0x73U, 0xD7U, 0x68U, 0x9EU, 0x45U, 0xC1U, 0x85U, 0xD9U, + 0x15U, 0x6EU, 0xCAU, 0xCCU, 0x75U, 0x62U, 0x20U, 0x27U, + 0x26U, 0x6AU, 0xFAU, 0x5FU, 0xB4U, 0x9FU, 0xDFU, 0x2EU, + 0x3DU, 0x5BU, 0xE5U, 0x2BU, 0xEEU, 0x56U, 0x5CU, 0x91U, + 0x28U, 0x56U, 0x7DU, 0x16U, 0x78U, 0x63U, 0xB5U, 0x3BU, + 0x51U, 0xA3U, 0x96U, 0x52U, 0xDAU, 0x8EU, 0xBBU, 0x92U, + 0xA0U, 0xD3U, 0xBDU, 0xB8U, 0xA1U, 0x4CU, 0x83U, 0xEDU, + 0x4EU, 0x29U, 0xBEU, 0x9FU, 0x73U, 0x55U, 0x47U, 0x7AU, + 0x31U, 0x30U, 0xFBU, 0x41U, 0x9DU, 0x89U, 0x26U, 0xF6U, + 0x19U, 0x48U, 0x6CU, 0xB9U, 0xD0U, 0x11U, 0x8DU, 0xF8U, + 0x8FU, 0x0FU, 0xB1U, 0x15U, 0x96U, 0xA9U, 0x06U, 0x4EU, + 0x01U, 0xCCU, 0x48U, 0xBDU, 0x65U, 0x2FU, 0x27U, 0x67U, + 0x74U, 0x89U, 0x54U, 0x24U, 0x88U, 0xF8U, 0x1EU, 0x90U, + 0xFBU, 0xFFU, 0xD1U, 0x57U, 0xE2U, 0x95U, 0x97U, 0x2BU, + 0x67U, 0x6EU, 0x6CU, 0xACU, 0x63U, 0x2CU, 0x96U, 0x61U, + 0xBEU, 0x58U, 0xD8U, 0xE4U, 0x0FU, 0x94U, 0x27U, 0x4AU, + 0x75U, 0x1CU, 0xE1U, 0x49U, 0xCDU, 0xFCU, 0x17U, 0xEAU, + 0x68U, 0x0EU, 0x1AU, 0x86U, 0xFBU, 0xF6U, 0x27U, 0x87U, + 0x48U, 0xBFU, 0x49U, 0x9AU, 0xB2U, 0x9EU, 0xAAU, 0xA9U, + 0x7DU, 0x30U, 0x0AU, 0x21U, 0x16U, 0xD5U, 0x82U, 0x86U, + 0x11U, 0x0EU, 0x9FU, 0xB0U, 0xC5U, 0x1CU, 0xBAU, 0xA7U, + 0xB1U, 0x31U, 0x49U, 0x41U, 0x27U, 0x26U, 0xCEU, 0xDDU, + 0xC4U, 0x45U, 0xA8U, 0xD5U, 0xC0U, 0x11U, 0xACU, 0xCCU, + 0x9CU, 0x2EU, 0x04U, 0xB0U, 0xF8U, 0x87U, 0x29U, 0x8EU, + 0x0FU, 0x53U, 0xF9U, 0xC9U, 0x69U, 0xFFU, 0x17U, 0x18U, + 0x25U, 0x95U, 0x9EU, 0x88U, 0x03U, 0xC7U, 0xE9U, 0xC5U, + 0xC6U, 0x2AU, 0xD0U, 0x91U, 0x7DU, 0x93U, 0xBDU, 0x77U, + 0xB8U, 0xF1U, 0x5FU, 0x8CU, 0x83U, 0xE1U, 0x85U, 0x65U, + 0x36U, 0xFAU, 0x43U, 0x90U, 0xBCU, 0x8EU, 0x12U, 0x1AU, + 0xF0U, 0xF3U, 0x04U, 0x1FU, 0x77U, 0x6FU, 0xB8U, 0x52U, + 0xFDU, 0xA3U, 0x6BU, 0x3DU, 0xFEU, 0xD8U, 0x86U, 0x14U, + 0x10U, 0xFFU, 0xCFU, 0xF2U, 0xC7U, 0x06U, 0xE9U, 0x02U, + 0x5CU, 0xFDU, 0x39U, 0xBBU, 0x3CU, 0x68U, 0xA2U, 0xBAU, + 0x84U, 0x02U, 0xDAU, 0xD2U, 0x10U, 0x80U, 0xD6U, 0xCAU, + 0xEAU, 0xDBU, 0xB9U, 0xAEU, 0xAEU, 0x85U, 0xBEU, 0xCDU, + 0x72U, 0xCFU, 0xCFU, 0x6CU, 0xA0U, 0xFBU, 0x5CU, 0x74U, + 0xADU, 0x4EU, 0x92U, 0x37U, 0xDBU, 0xD5U, 0x28U, 0x71U, + 0x35U, 0xD0U, 0xACU, 0xE7U, 0x71U, 0xE1U, 0xB7U, 0x9AU, + 0x2EU, 0x3FU, 0x8DU, 0xB8U, 0x10U, 0xC1U, 0xEEU, 0x35U, + 0x0BU, 0x83U, 0xA3U, 0xF0U, 0xBAU, 0xFCU, 0x75U, 0x43U, + 0x95U, 0x86U, 0x4CU, 0x0AU, 0x22U, 0xE8U, 0xDCU, 0x7DU, + 0x6EU, 0xB8U, 0xF8U, 0xE2U, 0x97U, 0x57U, 0x06U, 0xB4U, + 0x89U, 0xCAU, 0x9DU, 0xD5U, 0xDEU, 0xB6U, 0x48U, 0xCDU, + 0x29U, 0x3CU, 0xDFU, 0x7EU, 0x1EU, 0x37U, 0xCEU, 0x48U, + 0x20U, 0x5CU, 0xE3U, 0xCDU, 0x2FU, 0xA8U, 0xE5U, 0xC0U, + 0xB7U, 0xABU, 0xDFU, 0xDBU, 0x8DU, 0xD8U, 0x5DU, 0xF7U, + 0xA7U, 0x5CU, 0xF7U, 0xFFU, 0xD2U, 0x04U, 0xA5U, 0xE1U, + 0x35U, 0xE3U, 0x67U, 0xCEU, 0x42U, 0xC1U, 0x3EU, 0xABU, + 0x4AU, 0xFFU, 0x02U, 0x9AU, 0x94U, 0x9CU, 0x9AU, 0xC5U, + 0xDCU, 0xC1U, 0x50U, 0x52U, 0x1CU, 0x04U, 0xF9U, 0x23U, + 0x6DU, 0xA6U, 0x5AU, 0x9BU, 0xAAU, 0x5EU, 0x08U, 0xD1U, + 0xCCU, 0x35U, 0x29U, 0xF5U, 0x3DU, 0xAAU, 0xB3U, 0x25U, + 0xB6U, 0x07U, 0x29U, 0x4DU, 0x75U, 0x3CU, 0xADU, 0x17U, + 0xBEU, 0xD5U, 0xC0U, 0xDFU, 0x05U, 0xFEU, 0xB8U, 0x2DU, + 0x52U, 0xECU, 0xA7U, 0x67U, 0x6EU, 0xBAU, 0x32U, 0xE4U, + 0xD6U, 0x31U, 0x13U, 0x83U, 0xFDU, 0xEBU, 0xEBU, 0x91U, + + + ) + + val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() + val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() + val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() + val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true) + assertTrue { + expectedWithXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) + } + } + + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt new file mode 100644 index 0000000..3c2f57d --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt @@ -0,0 +1,293 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.blake2b + +import kotlin.test.Test +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 14-Jul-2019 + */ +@ExperimentalUnsignedTypes +@ExperimentalStdlibApi +class Blake2BTest { + + @Test + fun testMultipleBlocks() { + val test = "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + val result = Blake2b.digest(test) + //Generated with b2sum 8.31 + val expectedResult = ubyteArrayOf( + //@formatter:off + 0x2fU, 0x49U, 0xaeU, 0xb6U, 0x13U, 0xe3U, 0x4eU, 0x92U, 0x4eU, 0x17U, 0x5aU, 0x6aU, 0xf2U, 0xfaU, 0xadU, + 0x7bU, 0xc7U, 0x82U, 0x35U, 0xf9U, 0xc5U, 0xe4U, 0x61U, 0xc6U, 0x8fU, 0xd5U, 0xb4U, 0x07U, 0xeeU, 0x8eU, + 0x2fU, 0x0dU, 0x2fU, 0xb4U, 0xc0U, 0x7dU, 0x7eU, 0x4aU, 0x72U, 0x40U, 0x46U, 0x12U, 0xd9U, 0x28U, 0x99U, + 0xafU, 0x8aU, 0x32U, 0x8fU, 0x3bU, 0x61U, 0x4eU, 0xd7U, 0x72U, 0x44U, 0xb4U, 0x81U, 0x15U, 0x1dU, 0x40U, + 0xb1U, 0x1eU, 0x32U, 0xa4U + //@formatter:on + ) + + assertTrue { + result.contentEquals(expectedResult) + } + } + + @Test + fun singleBlockTest() { + val test = "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + "1234567890" + + + val result = Blake2b.digest(test) + val expectedResultString = "800bb78cd4da18995c8074713bb674" + + "3cd94b2b6490a693fe4000ed00833b88b7b474d94af9cfed246b1b" + + "4ce1935a76154d7ea7c410493557741d18ec3a08da75" + val expectedResult = expectedResultString.chunked(2).map { it.toUByte(16) }.toUByteArray() + + assertTrue { + result.contentEquals(expectedResult) + } + } + + + @Test + fun testDigest() { + val test = "111111111122222222223333333333333" + + val result = Blake2b.digest(test) + //Generated with b2sum 8.31 + val expectedResult = ubyteArrayOf( + //@formatter:off + 0xe0U, 0xabU, 0xb7U, 0x5dU, 0xb2U, 0xc8U, 0xe1U, 0x3cU, 0x5fU, 0x1dU, 0x9fU, 0x55U, 0xc8U, 0x4eU, 0xacU, 0xd7U, + 0xa8U, 0x44U, 0x57U, 0x9bU, 0xc6U, 0x9cU, 0x47U, 0x26U, 0xebU, 0xeaU, 0x2bU, 0xafU, 0x9eU, 0x44U, 0x16U, 0xebU, + 0xb8U, 0x0aU, 0xc5U, 0xfbU, 0xb0U, 0xe8U, 0xe5U, 0x6eU, 0xc5U, 0x49U, 0x0dU, 0x75U, 0x59U, 0x32U, 0x13U, 0xb4U, + 0x76U, 0x50U, 0x5eU, 0x6aU, 0xd8U, 0x74U, 0x67U, 0x14U, 0x64U, 0xb0U, 0xf8U, 0xb5U, 0x50U, 0x60U, 0x62U, 0xfbU + //@formatter:on + ) + + assertTrue { + result.contentEquals(expectedResult) + } + + } + + @Test + fun testFigestWithKey() { + val test = "abc" + val key = "key" + + val result = Blake2b.digest(test, key) + + assertTrue { + result.isNotEmpty() + } + val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" + + "6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1") + .chunked(2).map { it.toUByte(16) }.toUByteArray() + + assertTrue { + result.contentEquals(expectedResult) + } + } + + + @Test + fun testDigestFromRfc() { + val test = "abc" + + val result = Blake2b.digest(test) + //@formatter:off + val expectedResult = ubyteArrayOf( + + 0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U, + 0x4CU,0x21U,0x2FU,0x14U,0x68U,0x5AU,0xC4U,0xB7U,0x4BU,0x12U,0xBBU,0x6FU,0xDBU,0xFFU,0xA2U,0xD1U, + 0x7DU,0x87U,0xC5U,0x39U,0x2AU,0xABU,0x79U,0x2DU,0xC2U,0x52U,0xD5U,0xDEU,0x45U,0x33U,0xCCU,0x95U, + 0x18U,0xD3U,0x8AU,0xA8U,0xDBU,0xF1U,0x92U,0x5AU,0xB9U,0x23U,0x86U,0xEDU,0xD4U,0x00U,0x99U,0x23U + + ) + //@formatter:on + assertTrue { + result.contentEquals(expectedResult) + } + + } + + val message = arrayOf( + 0x0000000000636261UL, 0x0000000000000000UL, 0x0000000000000000UL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, + 0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL, + 0x0000000000000000UL + ) + + val mixChain = arrayOf( + arrayOf( + 0x6A09E667F2BDC948UL, 0xBB67AE8584CAA73BUL, 0x3C6EF372FE94F82BUL, + 0xA54FF53A5F1D36F1UL, 0x510E527FADE682D1UL, 0x9B05688C2B3E6C1FUL, + 0x1F83D9ABFB41BD6BUL, 0x5BE0CD19137E2179UL, 0x6A09E667F3BCC908UL, + 0xBB67AE8584CAA73BUL, 0x3C6EF372FE94F82BUL, 0xA54FF53A5F1D36F1UL, + 0x510E527FADE682D2UL, 0x9B05688C2B3E6C1FUL, 0xE07C265404BE4294UL, + 0x5BE0CD19137E2179UL + ), + arrayOf( + 0x86B7C1568029BB79UL, 0xC12CBCC809FF59F3UL, 0xC6A5214CC0EACA8EUL, + 0x0C87CD524C14CC5DUL, 0x44EE6039BD86A9F7UL, 0xA447C850AA694A7EUL, + 0xDE080F1BB1C0F84BUL, 0x595CB8A9A1ACA66CUL, 0xBEC3AE837EAC4887UL, + 0x6267FC79DF9D6AD1UL, 0xFA87B01273FA6DBEUL, 0x521A715C63E08D8AUL, + 0xE02D0975B8D37A83UL, 0x1C7B754F08B7D193UL, 0x8F885A76B6E578FEUL, + 0x2318A24E2140FC64UL + ), + arrayOf( + 0x53281E83806010F2UL, 0x3594B403F81B4393UL, 0x8CD63C7462DE0DFFUL, + 0x85F693F3DA53F974UL, 0xBAABDBB2F386D9AEUL, 0xCA5425AEC65A10A8UL, + 0xC6A22E2FF0F7AA48UL, 0xC6A56A51CB89C595UL, 0x224E6A3369224F96UL, + 0x500E125E58A92923UL, 0xE9E4AD0D0E1A0D48UL, 0x85DF9DC143C59A74UL, + 0x92A3AAAA6D952B7FUL, 0xC5FDF71090FAE853UL, 0x2A8A40F15A462DD0UL, + 0x572D17EFFDD37358UL + ), + arrayOf( + 0x60ED96AA7AD41725UL, 0xE46A743C71800B9DUL, 0x1A04B543A01F156BUL, + 0xA2F8716E775C4877UL, 0xDA0A61BCDE4267EAUL, 0xB1DD230754D7BDEEUL, + 0x25A1422779E06D14UL, 0xE6823AE4C3FF58A5UL, 0xA1677E19F37FD5DAUL, + 0x22BDCE6976B08C51UL, 0xF1DE8696BEC11BF1UL, 0xA0EBD586A4A1D2C8UL, + 0xC804EBAB11C99FA9UL, 0x8E0CEC959C715793UL, 0x7C45557FAE0D4D89UL, + 0x716343F52FDD265EUL + ), + arrayOf( + 0xBB2A77D3A8382351UL, 0x45EB47971F23B103UL, 0x98BE297F6E45C684UL, + 0xA36077DEE3370B89UL, 0x8A03C4CB7E97590AUL, 0x24192E49EBF54EA0UL, + 0x4F82C9401CB32D7AUL, 0x8CCD013726420DC4UL, 0xA9C9A8F17B1FC614UL, + 0x55908187977514A0UL, 0x5B44273E66B19D27UL, 0xB6D5C9FCA2579327UL, + 0x086092CFB858437EUL, 0x5C4BE2156DBEECF9UL, 0x2EFEDE99ED4EFF16UL, + 0x3E7B5F234CD1F804UL + ), + arrayOf( + 0xC79C15B3D423B099UL, 0x2DA2224E8DA97556UL, 0x77D2B26DF1C45C55UL, + 0x8934EB09A3456052UL, 0x0F6D9EEED157DA2AUL, 0x6FE66467AF88C0A9UL, + 0x4EB0B76284C7AAFBUL, 0x299C8E725D954697UL, 0xB2240B59E6D567D3UL, + 0x2643C2370E49EBFDUL, 0x79E02EEF20CDB1AEUL, 0x64B3EED7BB602F39UL, + 0xB97D2D439E4DF63DUL, 0xC718E755294C9111UL, 0x1F0893F2772BB373UL, + 0x1205EA4A7859807DUL + ), + arrayOf( + 0xE58F97D6385BAEE4UL, 0x7640AA9764DA137AUL, 0xDEB4C7C23EFE287EUL, + 0x70F6F41C8783C9F6UL, 0x7127CD48C76A7708UL, 0x9E472AF0BE3DB3F6UL, + 0x0F244C62DDF71788UL, 0x219828AA83880842UL, 0x41CCA9073C8C4D0DUL, + 0x5C7912BC10DF3B4BUL, 0xA2C3ABBD37510EE2UL, 0xCB5668CC2A9F7859UL, + 0x8733794F07AC1500UL, 0xC67A6BE42335AA6FUL, 0xACB22B28681E4C82UL, + 0xDB2161604CBC9828UL + ), + arrayOf( + 0x6E2D286EEADEDC81UL, 0xBCF02C0787E86358UL, 0x57D56A56DD015EDFUL, + 0x55D899D40A5D0D0AUL, 0x819415B56220C459UL, 0xB63C479A6A769F02UL, + 0x258E55E0EC1F362AUL, 0x3A3B4EC60E19DFDCUL, 0x04D769B3FCB048DBUL, + 0xB78A9A33E9BFF4DDUL, 0x5777272AE1E930C0UL, 0x5A387849E578DBF6UL, + 0x92AAC307CF2C0AFCUL, 0x30AACCC4F06DAFAAUL, 0x483893CC094F8863UL, + 0xE03C6CC89C26BF92UL + ), + arrayOf( + 0xFFC83ECE76024D01UL, 0x1BE7BFFB8C5CC5F9UL, 0xA35A18CBAC4C65B7UL, + 0xB7C2C7E6D88C285FUL, 0x81937DA314A50838UL, 0xE1179523A2541963UL, + 0x3A1FAD7106232B8FUL, 0x1C7EDE92AB8B9C46UL, 0xA3C2D35E4F685C10UL, + 0xA53D3F73AA619624UL, 0x30BBCC0285A22F65UL, 0xBCEFBB6A81539E5DUL, + 0x3841DEF6F4C9848AUL, 0x98662C85FBA726D4UL, 0x7762439BD5A851BDUL, + 0xB0B9F0D443D1A889UL + ), + arrayOf( + 0x753A70A1E8FAEADDUL, 0x6B0D43CA2C25D629UL, 0xF8343BA8B94F8C0BUL, + 0xBC7D062B0DB5CF35UL, 0x58540EE1B1AEBC47UL, 0x63C5B9B80D294CB9UL, + 0x490870ECAD27DEBDUL, 0xB2A90DDF667287FEUL, 0x316CC9EBEEFAD8FCUL, + 0x4A466BCD021526A4UL, 0x5DA7F7638CEC5669UL, 0xD9C8826727D306FCUL, + 0x88ED6C4F3BD7A537UL, 0x19AE688DDF67F026UL, 0x4D8707AAB40F7E6DUL, + 0xFD3F572687FEA4F1UL + ), + arrayOf( + 0xE630C747CCD59C4FUL, 0xBC713D41127571CAUL, 0x46DB183025025078UL, + 0x6727E81260610140UL, 0x2D04185EAC2A8CBAUL, 0x5F311B88904056ECUL, + 0x40BD313009201AABUL, 0x0099D4F82A2A1EABUL, 0x6DD4FBC1DE60165DUL, + 0xB3B0B51DE3C86270UL, 0x900AEE2F233B08E5UL, 0xA07199D87AD058D8UL, + 0x2C6B25593D717852UL, 0x37E8CA471BEAA5F8UL, 0x2CFC1BAC10EF4457UL, + 0x01369EC18746E775UL + ), + arrayOf( + 0xE801F73B9768C760UL, 0x35C6D22320BE511DUL, 0x306F27584F65495EUL, + 0xB51776ADF569A77BUL, 0xF4F1BE86690B3C34UL, 0x3CC88735D1475E4BUL, + 0x5DAC67921FF76949UL, 0x1CDB9D31AD70CC4EUL, 0x35BA354A9C7DF448UL, + 0x4929CBE45679D73EUL, 0x733D1A17248F39DBUL, 0x92D57B736F5F170AUL, + 0x61B5C0A41D491399UL, 0xB5C333457E12844AUL, 0xBD696BE010D0D889UL, + 0x02231E1A917FE0BDUL + ), + arrayOf( + 0x12EF8A641EC4F6D6UL, 0xBCED5DE977C9FAF5UL, 0x733CA476C5148639UL, + 0x97DF596B0610F6FCUL, 0xF42C16519AD5AFA7UL, 0xAA5AC1888E10467EUL, + 0x217D930AA51787F3UL, 0x906A6FF19E573942UL, 0x75AB709BD3DCBF24UL, + 0xEE7CE1F345947AA4UL, 0xF8960D6C2FAF5F5EUL, 0xE332538A36B6D246UL, + 0x885BEF040EF6AA0BUL, 0xA4939A417BFB78A3UL, 0x646CBB7AF6DCE980UL, + 0xE813A23C60AF3B82UL + ) + ) + + @Test + fun testMixRound() { + for (i in 0 until mixChain.size - 1) { + val inputRound = mixChain[i] + val round = i + val result = Blake2b.mixRound(inputRound, message, round) + val expectedResult = mixChain[i + 1] + assertTrue { + result.contentEquals(expectedResult) + } + } + + + } + + @Test + fun testInvalidHashLength() { + val test = "1234567890" + assertFailsWith(RuntimeException::class) { + val result = Blake2b.digest(inputString = test, hashLength = 65) + } + } + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt new file mode 100644 index 0000000..91ddf8f --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.blake2b + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 20-Jul-2019 + */ +@ExperimentalUnsignedTypes +@ExperimentalStdlibApi +class Blake2bInstanceTest { + + @Test + fun testUpdatableBlake2b() { + val updates = 14 + val input = "1234567890" + val expectedResult = ubyteArrayOf( + //@formatter:off + 0x2fU, 0x49U, 0xaeU, 0xb6U, 0x13U, 0xe3U, 0x4eU, 0x92U, 0x4eU, 0x17U, 0x5aU, 0x6aU, 0xf2U, 0xfaU, 0xadU, + 0x7bU, 0xc7U, 0x82U, 0x35U, 0xf9U, 0xc5U, 0xe4U, 0x61U, 0xc6U, 0x8fU, 0xd5U, 0xb4U, 0x07U, 0xeeU, 0x8eU, + 0x2fU, 0x0dU, 0x2fU, 0xb4U, 0xc0U, 0x7dU, 0x7eU, 0x4aU, 0x72U, 0x40U, 0x46U, 0x12U, 0xd9U, 0x28U, 0x99U, + 0xafU, 0x8aU, 0x32U, 0x8fU, 0x3bU, 0x61U, 0x4eU, 0xd7U, 0x72U, 0x44U, 0xb4U, 0x81U, 0x15U, 0x1dU, 0x40U, + 0xb1U, 0x1eU, 0x32U, 0xa4U + //@formatter:on + ) + + val blake2b = Blake2b() + for (i in 0 until updates) { + blake2b.update(input) + } + val result = blake2b.digest() + + assertTrue { + result.contentEquals(expectedResult) + } + } + + @Test + fun testDigestToString() { + val updates = 14 + val input = "1234567890" + val expectedResult = "2F49AEB613E34E924E175A6AF2FAAD7BC78235F9C5E461C68FD5B47E".toLowerCase() + + "E8E2FD2FB4C07D7E4A72404612D92899AF8A328F3B614ED77244B481151D40B11E32A4".toLowerCase() + + val blake2b = Blake2b() + for (i in 0 until updates) { + blake2b.update(input) + } + val result = blake2b.digestString() + assertTrue { + result == expectedResult + } + } + + @Test + fun testDigestWithKey() { + val test = "abc" + val key = "key" + val blake2b = Blake2b(key) + blake2b.update(test) + val result = blake2b.digest() + + assertTrue { + result.isNotEmpty() + } + val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" + + "6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1") + .chunked(2).map { it.toUByte(16) }.toUByteArray() + + assertTrue { + result.contentEquals(expectedResult) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt new file mode 100644 index 0000000..eae5b08 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt @@ -0,0 +1,1602 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.blake2b + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 15-Jul-2019 + */ +data class KnownAnswerTest( + val input: String, + val key: String, + val hash: String +) + +@ExperimentalUnsignedTypes +@ExperimentalStdlibApi +class Blake2bKnowAnswerTests { + @Test + fun knownAnswerTest() { + kat.forEach { + val parsedInput = it.input.chunked(2).map { it.toUByte(16) }.toUByteArray() + val result = Blake2b.digest( + inputMessage = parsedInput, + key = it.key.chunked(2).map { it.toUByte(16) }.toUByteArray() + ) + assertTrue { + result.contentEquals(it.hash.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + } + + @Test + fun knownAnswerTestInstance() { + + kat.forEach { kat -> + val parsedInput = kat.input.chunked(2).map { it.toUByte(16) }.toUByteArray() + val chunkedInput = parsedInput.toList().chunked(128).map { it.toUByteArray() } + val blake2b = Blake2b(key = kat.key.chunked(2).map { it.toUByte(16) }.toUByteArray()) + chunkedInput.forEach { blake2b.update(it) } + val result = blake2b.digest() + assertTrue("KAT ${kat.input} \nkey: ${kat.key} \nexpected: {${kat.hash}") { + result.contentEquals(kat.hash.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + } + + val kat = arrayOf( + KnownAnswerTest( + input = "", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568" + ), + + KnownAnswerTest( + input = "00", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd" + ), + + KnownAnswerTest( + input = "0001", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965" + ), + + KnownAnswerTest( + input = "000102", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1" + ), + + KnownAnswerTest( + input = "00010203", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac" + ), + + KnownAnswerTest( + input = "0001020304", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb" + ), + + KnownAnswerTest( + input = "000102030405", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f" + ), + + KnownAnswerTest( + input = "00010203040506", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52" + ), + + KnownAnswerTest( + input = "0001020304050607", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9" + ), + + KnownAnswerTest( + input = "000102030405060708", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637" + ), + + KnownAnswerTest( + input = "00010203040506070809", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd" + ), + + KnownAnswerTest( + input = "000102030405060708090a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f10", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f1011", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f10111213", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f1011121314", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f10111213141516", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f1011121314151617", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f10111213141516171819", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454647", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354555657", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556575859", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364656667", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566676869", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374757677", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576777879", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384858687", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586878889", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394959697", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596979899", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aa", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaab", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabac", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacad", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadae", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9ba", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babb", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbc", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbd", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9ca", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacb", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcc", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdce", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9da", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcddde", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9ea", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebec", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebeced", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedee", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fa", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafb", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfc", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9" + ), + + KnownAnswerTest( + input = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", + key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + hash = "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461" + ) + ) +} diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt new file mode 100644 index 0000000..39b6c24 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.sha + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 17-Jul-2019 + */ +@ExperimentalUnsignedTypes +class Sha256Test { + + @ExperimentalStdlibApi + @Test + fun testWellKnownValue() { + + val result = Sha256.digest(inputString = "abc") + val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownDoubleBlock() { + + val resultDoubleBlock = Sha256.digest(inputString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + val expectedResultForDoubleBlock = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnown3() { //It's good that I'm consistent with names. + + + val resultDoubleBlock = Sha256.digest(inputString = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) + val expectedResultForDoubleBlock = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownLong() { + val inputBuilder = StringBuilder() + for (i in 0 until 1000000) { + inputBuilder.append("a") + } + val resultDoubleBlock = Sha256.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val expectedResultForDoubleBlock = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt new file mode 100644 index 0000000..bdb0db4 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.sha + +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 17-Jul-2019 + */ +@ExperimentalUnsignedTypes +class Sha256UpdatableTest { + + @ExperimentalStdlibApi + @Test + fun testWellKnownValue() { + val sha256 = Sha256() + sha256.update("abc") + val result = sha256.digest() + val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownDoubleBlock() { + val sha256 = Sha256() + sha256.update(data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + val resultDoubleBlock = sha256.digest() + println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) + val expectedResultForDoubleBlock = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnown3() { //It's good that I'm consistent with names. + val sha256 = Sha256() + sha256.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + val resultDoubleBlock = sha256.digest() + println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) + val expectedResultForDoubleBlock = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownLong() { + val sha256 = Sha256() + for (i in 0 until 10000) { + sha256.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + } + val resultDoubleBlock = sha256.digest() + val expectedResultForDoubleBlock = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @Ignore() + @ExperimentalStdlibApi + @Test + fun testWellKnownLonger() { + val sha256 = Sha256() + for (i in 0 until 16_777_216) { + if (i % 10000 == 0) { + println("$i/16777216") + } + sha256.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno") + } + val resultDoubleBlock = sha256.digest() + val expectedResultForDoubleBlock = "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt new file mode 100644 index 0000000..c83c85d --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.sha + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 17-Jul-2019 + */ +class Sha512Test { + + @ExperimentalStdlibApi + @Test + fun testWellKnownValue() { + + val result = Sha512.digest(inputMessage = "abc".encodeToByteArray().map { it.toUByte() }.toUByteArray()) + println(result.map {it.toString(16)}) + val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalUnsignedTypes + @ExperimentalStdlibApi + @Test + fun testWellKnown3() { + val sha512 = Sha512() + sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + val resultDoubleBlock = sha512.digest() + val expectedResultForDoubleBlock = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownLong() { + val inputBuilder = StringBuilder() + for (i in 0 until 1000000) { + inputBuilder.append("a") + } + val resultDoubleBlock = Sha512.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val expectedResultForDoubleBlock = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt new file mode 100644 index 0000000..e2471d9 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.hash.sha + +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-Jul-2019 + */ +class Sha512UpdatableTest { + @ExperimentalStdlibApi + @Test + fun testWellKnownValue() { + val sha512 = Sha512() + sha512.update("abc") + val result = sha512.digest() + val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + + + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownDoubleBlock() { + val sha512 = Sha512() + sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + val resultDoubleBlock = sha512.digest() + println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) + val expectedResultForDoubleBlock = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @ExperimentalStdlibApi + @Test + fun testWellKnownLong() { + val sha512 = Sha512() + for (i in 0 until 10000) { + sha512.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + } + val resultDoubleBlock = sha512.digest() + val expectedResultForDoubleBlock = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } + + @Ignore() //Interestingly enough I'm not the only one having trouble with this test. + @ExperimentalStdlibApi + @Test + fun testWellKnownLonger() { + val sha512 = Sha512() + for (i in 0 until 16_777_216) { + if (i % 10000 == 0) { + println("$i/16777216") + } + sha512.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno") + } + val resultDoubleBlock = sha512.digest() + val expectedResultForDoubleBlock = "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d77be6091b819ed352c2967a2e2d4fa5050723c9630691f1a05a7281dbe6c1086" + assertTrue { + resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/parallelization/CoroutinesDebugTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/parallelization/CoroutinesDebugTest.kt new file mode 100644 index 0000000..a6a0f05 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/parallelization/CoroutinesDebugTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.parallelization + +import com.ionspin.kotlin.crypto.util.testBlocking +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlin.test.Test +import kotlin.time.ExperimentalTime + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 17-May-2020 + */ +@ExperimentalTime +class CoroutinesDebugTest { + + @Test + fun debugTest() = testBlocking { + Coroutines14.argonParallel() + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt new file mode 100644 index 0000000..dc34234 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.symmetric + +import com.ionspin.kotlin.crypto.util.hexStringToUByteArray +import com.ionspin.kotlin.crypto.util.hexStringToUByteArray +import com.ionspin.kotlin.crypto.util.toHexString +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-Sep-2019 + */ +@ExperimentalUnsignedTypes +class AesCbcTest { + + @Test + fun testCbcEncryption() { + assertTrue { + val key = "4278b840fb44aaa757c1bf04acbe1a3e" + val iv = "57f02a5c5339daeb0a2908a06ac6393f" + val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" + val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" + val aesCbc = + AesCbc(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray()) + aesCbc.addData(plaintext.hexStringToUByteArray()) + val encrypted = aesCbc.encrypt() + println("Encrypted: ${encrypted.encryptedData.toHexString()}") + + expectedCipherText == encrypted.encryptedData.toHexString() && + iv == encrypted.initilizationVector.toHexString() + } + + + + } + + @Test + fun testEncryptionApi() { + assertTrue { + val keyString = "4278b840fb44aaa757c1bf04acbe1a3e" + val key = AesKey.Aes128Key(keyString) + + val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" + + val encryptedDataAndInitializationVector = AesCbc.encrypt(key, plainText.hexStringToUByteArray()) + val decrypted = AesCbc.decrypt( + key, + encryptedDataAndInitializationVector.encryptedData, + encryptedDataAndInitializationVector.initilizationVector + ) + plainText == decrypted.toHexString() + } + } + + @Test + fun testCbcDecryption() { + assertTrue { + val key = "4278b840fb44aaa757c1bf04acbe1a3e" + val iv = "57f02a5c5339daeb0a2908a06ac6393f" + val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" + val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" + val aesCbc = + AesCbc(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray()) + aesCbc.addData(cipherText.hexStringToUByteArray()) + val decrypted = aesCbc.decrypt() + println("Decrypted: ${decrypted.toHexString()}") + + expectedPlainText == decrypted.toHexString() + } + + + + } + + @Test + fun testDecryptionApi() { + assertTrue { + val key = "4278b840fb44aaa757c1bf04acbe1a3e" + val iv = "57f02a5c5339daeb0a2908a06ac6393f" + val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" + val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" + val decrypted = AesCbc.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray()) + println("Decrypted: ${decrypted.toHexString()}") + + expectedPlainText == decrypted.toHexString() + } + } + + + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt new file mode 100644 index 0000000..4b140b5 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.symmetric + +import com.ionspin.kotlin.crypto.util.hexStringToUByteArray +import com.ionspin.kotlin.crypto.util.toHexString +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 21-Sep-2019 + */ +@ExperimentalUnsignedTypes +class AesCtrTest { + + @Test + fun testCtrEncryption() { + assertTrue { + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" + val plaintext = + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" + val expectedCipherText = + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" + val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray()) + aesCtr.addData( + plaintext.hexStringToUByteArray() + ) + val encrypted = aesCtr.encrypt() + println("Encrypted: ${encrypted.encryptedData.toHexString()}") + + expectedCipherText == encrypted.encryptedData.toHexString() && + ic == encrypted.initialCounter.toHexString() + } + + } + + @Test + fun testEncryptionApi() { + val keyString = "4278b840fb44aaa757c1bf04acbe1a3e" + val key = AesKey.Aes128Key(keyString) + val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" + + val encryptedDataAndInitializationVector = AesCtr.encrypt(key, plainText.hexStringToUByteArray()) + val decrypted = AesCtr.decrypt( + key, + encryptedDataAndInitializationVector.encryptedData, + encryptedDataAndInitializationVector.initialCounter + ) + assertTrue { + plainText == decrypted.toHexString() + } + } + + @Test + fun testCtrDecryption() { + assertTrue { + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" + val cipherText = + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" + val expectedPlainText = + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" + val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray()) + aesCtr.addData(cipherText.hexStringToUByteArray()) + val decrypted = aesCtr.decrypt() + println("Decrypted: ${decrypted.toHexString()}") + expectedPlainText == decrypted.toHexString() + } + + + + } + + @Test + fun testCtrDecryptionApi() { + assertTrue { + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" + val cipherText = + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" + val expectedPlainText = + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" + val decrypted = AesCtr.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray()) + println("Decrypted: ${decrypted.toHexString()}") + expectedPlainText == decrypted.toHexString() + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt new file mode 100644 index 0000000..ca3ef4f --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt @@ -0,0 +1,269 @@ +package com.ionspin.kotlin.crypto.symmetric + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 10/Sep/2019 + */ +@ExperimentalUnsignedTypes +class AesTest { + + val irrelevantKey = "01234567890123345678901234567890" + val irrelevantInput = UByteArray(16) { 0U } + + @Test + fun testSubBytes() { + val fakeState = arrayOf( + ubyteArrayOf(0x53U, 0U, 0U, 0U), + ubyteArrayOf(0U, 0U, 0U, 0U), + ubyteArrayOf(0U, 0U, 0U, 0U), + ubyteArrayOf(0U, 0U, 0U, 0U) + ) + val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + fakeState.copyInto(aes.state) + aes.subBytes() + assertTrue { + aes.state[0][0] == 0xEDU.toUByte() + } + } + + @Test + fun testShiftRows() { + val fakeState = arrayOf( + ubyteArrayOf(0U, 1U, 2U, 3U), + ubyteArrayOf(0U, 1U, 2U, 3U), + ubyteArrayOf(0U, 1U, 2U, 3U), + ubyteArrayOf(0U, 1U, 2U, 3U) + ) + val expectedState = arrayOf( + ubyteArrayOf(0U, 1U, 2U, 3U), + ubyteArrayOf(1U, 2U, 3U, 0U), + ubyteArrayOf(2U, 3U, 0U, 1U), + ubyteArrayOf(3U, 0U, 1U, 2U) + ) + val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + fakeState.copyInto(aes.state) + aes.shiftRows() + assertTrue { + aes.state.contentDeepEquals(expectedState) + } + } + + @Test + fun testGaloisMultiply() { + //Samples from FIPS-197 + assertTrue { + val a = 0x57U + val b = 0x83U + val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte()) + c == 0xC1U.toUByte() + } + + assertTrue { + val a = 0x57U + val b = 0x13U + val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte()) + c == 0xFEU.toUByte() + } + + + } + + @Test + fun testMixColumns() { + //Test vectors from wikipedia + val fakeState = arrayOf( + ubyteArrayOf(0xdbU, 0xf2U, 0x01U, 0xc6U), + ubyteArrayOf(0x13U, 0x0aU, 0x01U, 0xc6U), + ubyteArrayOf(0x53U, 0x22U, 0x01U, 0xc6U), + ubyteArrayOf(0x45U, 0x5cU, 0x01U, 0xc6U) + ) + + val expectedState = arrayOf( + ubyteArrayOf(0x8eU, 0x9fU, 0x01U, 0xc6U), + ubyteArrayOf(0x4dU, 0xdcU, 0x01U, 0xc6U), + ubyteArrayOf(0xa1U, 0x58U, 0x01U, 0xc6U), + ubyteArrayOf(0xbcU, 0x9dU, 0x01U, 0xc6U) + ) + + val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + fakeState.copyInto(aes.state) + aes.mixColumns() + assertTrue { + aes.state.contentDeepEquals(expectedState) + } + + } + + @Test + fun testKeyExpansion() { + assertTrue { + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val expectedExpandedKey = uintArrayOf( + // @formatter:off + 0x2b7e1516U, 0x28aed2a6U, 0xabf71588U, 0x09cf4f3cU, 0xa0fafe17U, 0x88542cb1U, + 0x23a33939U, 0x2a6c7605U, 0xf2c295f2U, 0x7a96b943U, 0x5935807aU, 0x7359f67fU, + 0x3d80477dU, 0x4716fe3eU, 0x1e237e44U, 0x6d7a883bU, 0xef44a541U, 0xa8525b7fU, + 0xb671253bU, 0xdb0bad00U, 0xd4d1c6f8U, 0x7c839d87U, 0xcaf2b8bcU, 0x11f915bcU, + 0x6d88a37aU, 0x110b3efdU, 0xdbf98641U, 0xca0093fdU, 0x4e54f70eU, 0x5f5fc9f3U, + 0x84a64fb2U, 0x4ea6dc4fU, 0xead27321U, 0xb58dbad2U, 0x312bf560U, 0x7f8d292fU, + 0xac7766f3U, 0x19fadc21U, 0x28d12941U, 0x575c006eU, 0xd014f9a8U, 0xc9ee2589U, + 0xe13f0cc8U, 0xb6630ca6U + // @formatter:on + ).toTypedArray() + + + val aes = Aes(AesKey.Aes128Key(key), irrelevantInput) + val result = aes.expandedKey.map { + it.foldIndexed(0U) { index, acc, uByte -> + acc + (uByte.toUInt() shl (24 - index * 8)) + } + }.toTypedArray() + expectedExpandedKey.contentEquals(result) + } + + assertTrue { + val key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" + val expectedExpandedKey = uintArrayOf( + // @formatter:off + 0x8e73b0f7U, 0xda0e6452U, 0xc810f32bU, 0x809079e5U, 0x62f8ead2U, 0x522c6b7bU, + 0xfe0c91f7U, 0x2402f5a5U, 0xec12068eU, 0x6c827f6bU, 0x0e7a95b9U, 0x5c56fec2U, 0x4db7b4bdU, 0x69b54118U, + 0x85a74796U, 0xe92538fdU, 0xe75fad44U, 0xbb095386U, 0x485af057U, 0x21efb14fU, 0xa448f6d9U, 0x4d6dce24U, + 0xaa326360U, 0x113b30e6U, 0xa25e7ed5U, 0x83b1cf9aU, 0x27f93943U, 0x6a94f767U, 0xc0a69407U, 0xd19da4e1U, + 0xec1786ebU, 0x6fa64971U, 0x485f7032U, 0x22cb8755U, 0xe26d1352U, 0x33f0b7b3U, 0x40beeb28U, 0x2f18a259U, + 0x6747d26bU, 0x458c553eU, 0xa7e1466cU, 0x9411f1dfU, 0x821f750aU, 0xad07d753U, 0xca400538U, 0x8fcc5006U, + 0x282d166aU, 0xbc3ce7b5U, 0xe98ba06fU, 0x448c773cU, 0x8ecc7204U, 0x01002202U + // @formatter:on + ).toTypedArray() + + + val aes = Aes(AesKey.Aes192Key(key), irrelevantInput) + val result = aes.expandedKey.map { + it.foldIndexed(0U) { index, acc, uByte -> + acc + (uByte.toUInt() shl (24 - index * 8)) + } + }.toTypedArray() + expectedExpandedKey.contentEquals(result) + } + + assertTrue { + val key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" + + val expectedExpandedKey = uintArrayOf( + // @formatter:off + 0x603deb10U, 0x15ca71beU, 0x2b73aef0U, 0x857d7781U, 0x1f352c07U, 0x3b6108d7U, 0x2d9810a3U, 0x0914dff4U, + 0x9ba35411U, 0x8e6925afU, 0xa51a8b5fU, 0x2067fcdeU, 0xa8b09c1aU, 0x93d194cdU, 0xbe49846eU, 0xb75d5b9aU, + 0xd59aecb8U, 0x5bf3c917U, 0xfee94248U, 0xde8ebe96U, 0xb5a9328aU, 0x2678a647U, 0x98312229U, 0x2f6c79b3U, + 0x812c81adU, 0xdadf48baU, 0x24360af2U, 0xfab8b464U, 0x98c5bfc9U, 0xbebd198eU, 0x268c3ba7U, 0x09e04214U, + 0x68007bacU, 0xb2df3316U, 0x96e939e4U, 0x6c518d80U, 0xc814e204U, 0x76a9fb8aU, 0x5025c02dU, 0x59c58239U, + 0xde136967U, 0x6ccc5a71U, 0xfa256395U, 0x9674ee15U, 0x5886ca5dU, 0x2e2f31d7U, 0x7e0af1faU, 0x27cf73c3U, + 0x749c47abU, 0x18501ddaU, 0xe2757e4fU, 0x7401905aU, 0xcafaaae3U, 0xe4d59b34U, 0x9adf6aceU, 0xbd10190dU, + 0xfe4890d1U, 0xe6188d0bU, 0x046df344U, 0x706c631eU + // @formatter:on + ).toTypedArray() + + + val aes = Aes(AesKey.Aes256Key(key), irrelevantInput) + val result = aes.expandedKey.map { + it.foldIndexed(0U) { index, acc, uByte -> + acc + (uByte.toUInt() shl (24 - index * 8)) + } + }.toTypedArray() + expectedExpandedKey.contentEquals(result) + } + + } + + @Test + fun testEncryption() { + val input = "3243f6a8885a308d313198a2e0370734" + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val expectedResult = "3925841d02dc09fbdc118597196a0b32" + + val aes = Aes(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + val result = aes.encrypt() + assertTrue { + result.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + } + + @Test + fun testEncryptionAndDecryption() { + assertTrue { + val input = "3243f6a8885a308d313198a2e0370734" + val key = "2b7e151628aed2a6abf7158809cf4f3c" + val expectedResult = "3925841d02dc09fbdc118597196a0b32" + val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() + val aes = Aes(AesKey.Aes128Key(key), original) + val encrypted = aes.encrypt() + assertTrue { + encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted) + + decrypted.contentEquals(original) + } + assertTrue { + val input = "00112233445566778899aabbccddeeff" + val key = "000102030405060708090a0b0c0d0e0f" + val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a" + val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() + val aes = Aes(AesKey.Aes128Key(key), original) + val encrypted = aes.encrypt() + assertTrue { + encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + val aesDec = Aes(AesKey.Aes128Key(key), encrypted) + val decrypted = aesDec.decrypt() + assertTrue { + aesDec.expandedKey.contentDeepEquals(aes.expandedKey) + } + decrypted.contentEquals(original) + } + + assertTrue { + val input = "00112233445566778899aabbccddeeff" + val key = "000102030405060708090a0b0c0d0e0f" + val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a" + val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() + val encrypted = Aes.encrypt(AesKey.Aes128Key(key), original) + assertTrue { + encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted) + decrypted.contentEquals(original) + } + + assertTrue { + val input = "00112233445566778899aabbccddeeff" + val key = "000102030405060708090a0b0c0d0e0f1011121314151617" + val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191" + val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() + val encrypted = Aes.encrypt(AesKey.Aes192Key(key), original) + assertTrue { + encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + val decrypted = Aes.decrypt(AesKey.Aes192Key(key), encrypted) + decrypted.contentEquals(original) + } + + assertTrue { + val input = "00112233445566778899aabbccddeeff" + val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + val expectedResult = "8ea2b7ca516745bfeafc49904b496089" + val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() + val encrypted = Aes.encrypt(AesKey.Aes256Key(key), original) + assertTrue { + encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + } + val decrypted = Aes.decrypt(AesKey.Aes256Key(key), encrypted) + decrypted.contentEquals(original) + } + } + + + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/TestUtil.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/TestUtil.kt new file mode 100644 index 0000000..ab0598d --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/TestUtil.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.util + +import kotlinx.coroutines.CoroutineScope + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 20-Jul-2019 + */ +expect fun testBlocking(block : suspend () -> Unit) \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/UtilTest.kt b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/UtilTest.kt new file mode 100644 index 0000000..d038416 --- /dev/null +++ b/multiplatform-crypto-api/src/commonTest/kotlin/com/ionspin/kotlin/crypto/util/UtilTest.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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.ionspin.kotlin.crypto.util + +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 17-Jul-2019 + */ +@ExperimentalUnsignedTypes +class UtilTest { + + @Test + fun testSlicer() { + val array = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) + val chunked = array.chunked(2) + assertTrue { + chunked.size == 9 && chunked[8][0] == 17 + } + } + + @Test + fun testUIntToBigEndianArray() { + assertTrue { + val original = 1U + val converted = original.toBigEndianUByteArray() + converted[0] = 1U + true + } + assertTrue { + val original = 0xAABBCCDDU + val converted = original.toBigEndianUByteArray() + converted[0] == 0xAAU.toUByte() && + converted[1] == 0xBBU.toUByte() && + converted[2] == 0xCCU.toUByte() && + converted[3] == 0xDDU.toUByte() + + } + } + + @Test + fun testUIntToLittleEndianArray() { + assertTrue { + val original = 1U + val converted = original.toLittleEndianTypedUByteArray() + converted[3] = 1U + true + } + assertTrue { + val original = 0xAABBCCDDU + val converted = original.toLittleEndianTypedUByteArray() + converted[0] == 0xDDU.toUByte() && + converted[1] == 0xCCU.toUByte() && + converted[2] == 0xBBU.toUByte() && + converted[3] == 0xAAU.toUByte() + + } + assertTrue { + val original = 123456U + val converted = original.toLittleEndianTypedUByteArray() + converted[0] == 0x40U.toUByte() && + converted[1] == 0xE2U.toUByte() && + converted[2] == 0x01U.toUByte() && + converted[3] == 0x00U.toUByte() + + } + } + + @Test + fun testFromBigEndianByteArrayToLong() { + + assertTrue { + val ubyteArray = ubyteArrayOf(0xA1U, 0xA2U, 0xB1U, 0xB2U, 0xC1U, 0xC2U, 0xD1U, 0xD2U).toTypedArray() + val expected = 0xA1A2B1B2C1C2D1D2U + val reconstructed = ubyteArray.fromBigEndianArrayToULong(); + reconstructed == expected + } + + } + + @Test + fun testFromLittleEndianByteArrayToLong() { + + assertTrue { + val ubyteArray = ubyteArrayOf(0xA1U, 0xA2U, 0xB1U, 0xB2U, 0xC1U, 0xC2U, 0xD1U, 0xD2U).toTypedArray() + val expected = 0xD2D1C2C1B2B1A2A1UL + val reconstructed = ubyteArray.fromLittleEndianArrayToULong(); + reconstructed == expected + } + + } +} \ No newline at end of file diff --git a/multiplatform-crypto/build.gradle.kts b/multiplatform-crypto/build.gradle.kts index 2c6dde2..f329bd4 100644 --- a/multiplatform-crypto/build.gradle.kts +++ b/multiplatform-crypto/build.gradle.kts @@ -186,6 +186,7 @@ kotlin { implementation(kotlin(Deps.Common.test)) implementation(Deps.Common.coroutines) implementation(Deps.Common.kotlinBigNum) + implementation(project(":multiplatform-crypto-api")) } } val commonTest by getting { diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt new file mode 100644 index 0000000..86ddfa8 --- /dev/null +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt @@ -0,0 +1,14 @@ +package com.ionspin.kotlin.crypto + +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure +import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure +import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 24-May-2020 + */ +typealias Blake2bStateless = Blake2bPure.Companion +typealias Sha256Stateless = Sha256Pure.Companion +typealias Sha512Stateless = Sha512Pure.Companion \ No newline at end of file diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt similarity index 97% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt index c78c038..5ad92b8 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt @@ -19,9 +19,6 @@ package com.ionspin.kotlin.crypto.hash.blake2b import com.ionspin.kotlin.bignum.integer.BigInteger import com.ionspin.kotlin.bignum.integer.toBigInteger import com.ionspin.kotlin.crypto.* -import com.ionspin.kotlin.crypto.hash.StatelessHash -import com.ionspin.kotlin.crypto.hash.UpdatableHash -import com.ionspin.kotlin.crypto.util.chunked import com.ionspin.kotlin.crypto.util.rotateRight /** @@ -31,9 +28,9 @@ import com.ionspin.kotlin.crypto.util.rotateRight */ @ExperimentalUnsignedTypes -class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : UpdatableHash { +class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake2b { - companion object : StatelessHash { + companion object : Blake2bStatelessInterface { //Hack start //If this line is not included konanc 1.4-M1 fails to link because it cant find ByteArray which is //a backing class for UByteArray @@ -255,7 +252,7 @@ class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : Updatable requestedHashLenght ) - override val MAX_HASH_BYTES: Int = Blake2b.MAX_HASH_BYTES + override val MAX_HASH_BYTES: Int = Blake2bPure.MAX_HASH_BYTES var h = iv.copyOf() var counter = BigInteger.ZERO diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt similarity index 99% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt index ca2143f..ec646c1 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt @@ -16,7 +16,6 @@ package com.ionspin.kotlin.crypto.hash.sha -import com.ionspin.kotlin.crypto.util.chunked import com.ionspin.kotlin.crypto.hash.StatelessHash import com.ionspin.kotlin.crypto.hash.UpdatableHash import com.ionspin.kotlin.crypto.util.rotateRight @@ -30,12 +29,12 @@ import com.ionspin.kotlin.crypto.util.rotateRight @ExperimentalUnsignedTypes -class Sha256 : UpdatableHash { +class Sha256Pure : Sha256 { override val MAX_HASH_BYTES: Int = 32 - companion object : StatelessHash { + companion object : StatelessSha256 { const val BLOCK_SIZE = 512 const val BLOCK_SIZE_IN_BYTES = 64 const val UINT_MASK = 0xFFFFFFFFU diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt similarity index 99% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt index c58e562..955ee61 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt @@ -16,7 +16,6 @@ package com.ionspin.kotlin.crypto.hash.sha -import com.ionspin.kotlin.crypto.util.chunked import com.ionspin.kotlin.crypto.hash.StatelessHash import com.ionspin.kotlin.crypto.hash.UpdatableHash import com.ionspin.kotlin.crypto.util.rotateRight @@ -28,11 +27,11 @@ import com.ionspin.kotlin.crypto.util.rotateRight */ @ExperimentalUnsignedTypes -class Sha512 : UpdatableHash { +class Sha512Pure : Sha512 { override val MAX_HASH_BYTES: Int = 32 - companion object : StatelessHash { + companion object : StatelessSha512 { const val BLOCK_SIZE = 1024 const val BLOCK_SIZE_IN_BYTES = 128 const val CHUNK_SIZE = 80 diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt index 444ce02..707a664 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt @@ -1,406 +1,10 @@ -/* - * Copyright 2019 Ugljesa Jovanovic - * - * 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. - */ - -@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") - package com.ionspin.kotlin.crypto.keyderivation.argon2 -import com.ionspin.kotlin.bignum.integer.toBigInteger -import com.ionspin.kotlin.crypto.SRNG -import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters -import com.ionspin.kotlin.crypto.util.* /** * Created by Ugljesa Jovanovic * ugljesa.jovanovic@ionspin.com - * on 16-May-2020 + * on 24-May-2020 */ - -enum class ArgonType(val typeId: Int) { - Argon2d(0), Argon2i(1), Argon2id(2) -} - -data class SegmentPosition( - val iteration: Int, - val lane: Int, - val slice: Int -) - -data class ArgonResult( - val hashBytes: UByteArray, - val salt: UByteArray -) { - val hashString by lazy { hashBytes.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") } - val saltString by lazy { salt.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") } - -} - - - -@ExperimentalStdlibApi -class Argon2( - private val password: UByteArray, - private val salt: UByteArray = ubyteArrayOf(), - private val parallelism: Int = 1, - private val tagLength: UInt = 64U, - requestedMemorySize: UInt = 0U, - private val numberOfIterations: Int = 1, - private val key: UByteArray = ubyteArrayOf(), - private val associatedData: UByteArray = ubyteArrayOf(), - private val argonType: ArgonType = ArgonType.Argon2id -) : KeyDerivationFunction { - - companion object { - fun derive( - password: String, - salt: String? = null, - key: String, - associatedData: String, - parallelism: Int = 16, - tagLength: Int = 64, - memory: Int = 4096, - numberOfIterations: Int = 10, - ): ArgonResult { - val salt = SRNG.getRandomBytes(64) - val argon = Argon2( - password.encodeToByteArray().toUByteArray(), - salt, - parallelism, - tagLength.toUInt(), - memory.toUInt(), - numberOfIterations, - key.encodeToByteArray().toUByteArray(), - associatedData.encodeToByteArray().toUByteArray(), - ArgonType.Argon2id - ) - val resultArray = argon.derive() - return ArgonResult(resultArray, salt) - } - } - - constructor( - password: String, - salt: String = "", - parallelism: Int = 1, - tagLength: UInt = 64U, - requestedMemorySize: UInt = 0U, - numberOfIterations: Int = 10, - key: String = "", - associatedData: String = "", - argonType: ArgonType = ArgonType.Argon2id - ) : this( - password.encodeToByteArray().toUByteArray(), - salt.encodeToByteArray().toUByteArray(), - parallelism, - tagLength, - requestedMemorySize, - numberOfIterations, - key.encodeToByteArray().toUByteArray(), - associatedData.encodeToByteArray().toUByteArray(), - argonType - ) - - //We support only the latest version - private val versionNumber: UInt = 0x13U - - //Use either requested memory size, or default, or throw exception if the requested amount is less than 8*parallelism - private val memorySize = if (requestedMemorySize == 0U) { - ((8 * parallelism) * 2).toUInt() - } else { - requestedMemorySize - } - private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt()) - private val columnCount = (blockCount / parallelism.toUInt()).toInt() - private val segmentLength = columnCount / 4 - - private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i - - // State - private val matrix: ArgonMatrix - - init { - matrix = ArgonMatrix(columnCount, parallelism) - validateArgonParameters( - password, - salt, - parallelism, - tagLength, - requestedMemorySize, - numberOfIterations, - key, - associatedData, - argonType - ) - } - - - - private fun populateAddressBlock( - iteration: Int, - slice: Int, - lane: Int, - addressBlock: ArgonBlockPointer, - addressCounter: ULong - ): ArgonBlockPointer { - //Calculate first pass - val zeroesBlock = ArgonBlock() - val firstPass = compressionFunctionG( - zeroesBlock.getBlockPointer(), - ArgonBlock(iteration.toULong().toLittleEndianUByteArray() + - lane.toULong().toLittleEndianUByteArray() + - slice.toULong().toLittleEndianUByteArray() + - blockCount.toULong().toLittleEndianUByteArray() + - numberOfIterations.toULong().toLittleEndianUByteArray() + - argonType.typeId.toULong().toLittleEndianUByteArray() + - addressCounter.toLittleEndianUByteArray() + - UByteArray(968) { 0U } - ).getBlockPointer(), - addressBlock, - false - ) - val secondPass = compressionFunctionG( - zeroesBlock.getBlockPointer(), - firstPass, - firstPass, - false - ) - return secondPass - } - - - private fun computeReferenceBlockIndexes( - iteration: Int, - slice: Int, - lane: Int, - column: Int, - addressBlockPointer: ArgonBlockPointer? - ): Pair { - - val segmentIndex = (column % segmentLength) - val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block - val (j1, j2) = when (argonType) { - ArgonType.Argon2d -> { - val previousBlockStart = if (column == 0) { - matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane - } else { - matrix.getBlockPointer(lane, column - 1) - } - val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt() - val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt() - - Pair(first32Bit, second32Bit) - } - ArgonType.Argon2i -> { - val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8) - val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4) - Pair(first32Bit, second32Bit) - } - ArgonType.Argon2id -> { - if (iteration == 0 && (slice == 0 || slice == 1)) { - val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8) - val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4) - Pair(first32Bit, second32Bit) - } else { - val previousBlockStart = if (column == 0) { - matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane - } else { - matrix.getBlockPointer(lane, column - 1) - } - val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt() - val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt() - Pair(first32Bit, second32Bit) - } - - } - } - - //If this is first iteration and first slice, block is taken from the current lane - val l = if (iteration == 0 && slice == 0) { - lane - } else { - (j2.toBigInteger() % parallelism).intValue() - - } - - - val referenceAreaSize = if (iteration == 0) { - if (slice == 0) { - //All indices except the previous - segmentIndex - 1 - } else { - if (lane == l) { - //Same lane - column - 1 - } else { - slice * (columnCount / 4) + if (segmentIndex == 0) { // Check if column is first block of the SEGMENT - -1 - } else { - 0 - } - } - } - } else { - if (lane == l) { - columnCount - (columnCount / 4) + (segmentIndex - 1) - } else { - columnCount - (columnCount / 4) + if (segmentIndex == 0) { - -1 - } else { - 0 - } - } - } - - val x = (j1.toULong() * j1) shr 32 - val y = (referenceAreaSize.toULong() * x) shr 32 - val z = referenceAreaSize.toULong() - 1U - y - - val startPosition = if (iteration == 0) { - 0 - } else { - if (slice == 3) { - 0 - } else { - (slice + 1) * segmentLength - } - } - val absolutePosition = (startPosition + z.toInt()) % columnCount - - return Pair(l, absolutePosition) - } - - override fun derive(): UByteArray { - val blakeInput = parallelism.toUInt().toLittleEndianUByteArray() + - tagLength.toLittleEndianUByteArray() + - memorySize.toLittleEndianUByteArray() + - numberOfIterations.toUInt().toLittleEndianUByteArray() + - versionNumber.toLittleEndianUByteArray() + - argonType.typeId.toUInt().toLittleEndianUByteArray() + - password.size.toUInt().toLittleEndianUByteArray() + password + - salt.size.toUInt().toLittleEndianUByteArray() + salt + - key.size.toUInt().toLittleEndianUByteArray() + key + - associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData - val h0 = Blake2b.digest( - blakeInput - ) - - //Compute B[i][0] - for (i in 0 until parallelism) { - matrix.setBlockAt(i, 0, - argonBlake2bArbitraryLenghtHash( - (h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(), - 1024U - ) - ) - } - - //Compute B[i][1] - for (i in 0 until parallelism) { - matrix.setBlockAt(i, 1, - argonBlake2bArbitraryLenghtHash( - (h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(), - 1024U - ) - ) - } - //Run all iterations over all lanes and all segments - executeArgonWithSingleThread() - - - val acc = ArgonBlock(matrix.getBlockAt(0, columnCount - 1)) - val accPointer = acc.getBlockPointer() - for (i in 1 until parallelism) { - accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1)) - } - //Hash the xored last blocks - val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength) - matrix.clearMatrix() - return hash - - - } - - private fun executeArgonWithSingleThread() { - for (iteration in 0 until numberOfIterations) { - for (slice in 0 until 4) { - for (lane in 0 until parallelism) { - val segmentPosition = SegmentPosition(iteration, lane, slice) - processSegment(segmentPosition) - } - } - } - } - - private fun processSegment(segmentPosition: SegmentPosition) { - val iteration = segmentPosition.iteration - val slice = segmentPosition.slice - val lane = segmentPosition.lane - - var addressBlock: ArgonBlockPointer? = null - var addressCounter = 1UL //Starts from 1 in each segment as defined by the spec - - //Generate initial segment address block - if (useIndependentAddressing) { - addressBlock = ArgonBlock().getBlockPointer() - addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter) - addressCounter++ - } - val startColumn = if (iteration == 0 && slice == 0) { - 2 - } else { - slice * segmentLength - } - - - for (column in startColumn until (slice + 1) * segmentLength) { - val segmentIndex = column - (slice * segmentLength) - //Each address block contains 128 addresses, and we use one per iteration, - //so once we do 128 iterations we need to calculate a new address block - if (useIndependentAddressing && segmentIndex != 0 && segmentIndex % 128 == 0) { - addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock!!, addressCounter) - addressCounter++ - } - val previousColumn = if (column == 0) { - columnCount - 1 - } else { - column - 1 - } - val (l, z) = computeReferenceBlockIndexes( - iteration, - slice, - lane, - column, - addressBlock - ) - - matrix.setBlockAt(lane, column, - compressionFunctionG( - matrix.getBlockPointer(lane, previousColumn), - matrix.getBlockPointer(l,z), - matrix.getBlockPointer(lane,column), - true - ).getAsUByteArray() - ) - } - - } - - -} +interface Argon2 : KeyDerivationFunction \ No newline at end of file diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt new file mode 100644 index 0000000..099597c --- /dev/null +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt @@ -0,0 +1,405 @@ +/* + * Copyright 2019 Ugljesa Jovanovic + * + * 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. + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") + +package com.ionspin.kotlin.crypto.keyderivation.argon2 + +import com.ionspin.kotlin.bignum.integer.toBigInteger +import com.ionspin.kotlin.crypto.SRNG +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bStateless +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters +import com.ionspin.kotlin.crypto.util.* + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 16-May-2020 + */ + +enum class ArgonType(val typeId: Int) { + Argon2d(0), Argon2i(1), Argon2id(2) +} + +data class SegmentPosition( + val iteration: Int, + val lane: Int, + val slice: Int +) + +data class ArgonResult( + val hashBytes: UByteArray, + val salt: UByteArray +) { + val hashString by lazy { hashBytes.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") } + val saltString by lazy { salt.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") } + +} + + + +@ExperimentalStdlibApi +class Argon2Pure( + private val password: UByteArray, + private val salt: UByteArray = ubyteArrayOf(), + private val parallelism: Int = 1, + private val tagLength: UInt = 64U, + requestedMemorySize: UInt = 0U, + private val numberOfIterations: Int = 1, + private val key: UByteArray = ubyteArrayOf(), + private val associatedData: UByteArray = ubyteArrayOf(), + private val argonType: ArgonType = ArgonType.Argon2id +) : Argon2 { + + companion object { + fun derive( + password: String, + salt: String? = null, + key: String, + associatedData: String, + parallelism: Int = 16, + tagLength: Int = 64, + memory: Int = 4096, + numberOfIterations: Int = 10, + ): ArgonResult { + val salt = SRNG.getRandomBytes(64) + val argon = Argon2Pure( + password.encodeToByteArray().toUByteArray(), + salt, + parallelism, + tagLength.toUInt(), + memory.toUInt(), + numberOfIterations, + key.encodeToByteArray().toUByteArray(), + associatedData.encodeToByteArray().toUByteArray(), + ArgonType.Argon2id + ) + val resultArray = argon.derive() + return ArgonResult(resultArray, salt) + } + } + + constructor( + password: String, + salt: String = "", + parallelism: Int = 1, + tagLength: UInt = 64U, + requestedMemorySize: UInt = 0U, + numberOfIterations: Int = 10, + key: String = "", + associatedData: String = "", + argonType: ArgonType = ArgonType.Argon2id + ) : this( + password.encodeToByteArray().toUByteArray(), + salt.encodeToByteArray().toUByteArray(), + parallelism, + tagLength, + requestedMemorySize, + numberOfIterations, + key.encodeToByteArray().toUByteArray(), + associatedData.encodeToByteArray().toUByteArray(), + argonType + ) + + //We support only the latest version + private val versionNumber: UInt = 0x13U + + //Use either requested memory size, or default, or throw exception if the requested amount is less than 8*parallelism + private val memorySize = if (requestedMemorySize == 0U) { + ((8 * parallelism) * 2).toUInt() + } else { + requestedMemorySize + } + private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt()) + private val columnCount = (blockCount / parallelism.toUInt()).toInt() + private val segmentLength = columnCount / 4 + + private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i + + // State + private val matrix: ArgonMatrix + + init { + matrix = ArgonMatrix(columnCount, parallelism) + validateArgonParameters( + password, + salt, + parallelism, + tagLength, + requestedMemorySize, + numberOfIterations, + key, + associatedData, + argonType + ) + } + + + + private fun populateAddressBlock( + iteration: Int, + slice: Int, + lane: Int, + addressBlock: ArgonBlockPointer, + addressCounter: ULong + ): ArgonBlockPointer { + //Calculate first pass + val zeroesBlock = ArgonBlock() + val firstPass = compressionFunctionG( + zeroesBlock.getBlockPointer(), + ArgonBlock(iteration.toULong().toLittleEndianUByteArray() + + lane.toULong().toLittleEndianUByteArray() + + slice.toULong().toLittleEndianUByteArray() + + blockCount.toULong().toLittleEndianUByteArray() + + numberOfIterations.toULong().toLittleEndianUByteArray() + + argonType.typeId.toULong().toLittleEndianUByteArray() + + addressCounter.toLittleEndianUByteArray() + + UByteArray(968) { 0U } + ).getBlockPointer(), + addressBlock, + false + ) + val secondPass = compressionFunctionG( + zeroesBlock.getBlockPointer(), + firstPass, + firstPass, + false + ) + return secondPass + } + + + private fun computeReferenceBlockIndexes( + iteration: Int, + slice: Int, + lane: Int, + column: Int, + addressBlockPointer: ArgonBlockPointer? + ): Pair { + + val segmentIndex = (column % segmentLength) + val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block + val (j1, j2) = when (argonType) { + ArgonType.Argon2d -> { + val previousBlockStart = if (column == 0) { + matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane + } else { + matrix.getBlockPointer(lane, column - 1) + } + val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt() + val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt() + + Pair(first32Bit, second32Bit) + } + ArgonType.Argon2i -> { + val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8) + val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4) + Pair(first32Bit, second32Bit) + } + ArgonType.Argon2id -> { + if (iteration == 0 && (slice == 0 || slice == 1)) { + val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8) + val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4) + Pair(first32Bit, second32Bit) + } else { + val previousBlockStart = if (column == 0) { + matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane + } else { + matrix.getBlockPointer(lane, column - 1) + } + val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt() + val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt() + Pair(first32Bit, second32Bit) + } + + } + } + + //If this is first iteration and first slice, block is taken from the current lane + val l = if (iteration == 0 && slice == 0) { + lane + } else { + (j2.toBigInteger() % parallelism).intValue() + + } + + + val referenceAreaSize = if (iteration == 0) { + if (slice == 0) { + //All indices except the previous + segmentIndex - 1 + } else { + if (lane == l) { + //Same lane + column - 1 + } else { + slice * (columnCount / 4) + if (segmentIndex == 0) { // Check if column is first block of the SEGMENT + -1 + } else { + 0 + } + } + } + } else { + if (lane == l) { + columnCount - (columnCount / 4) + (segmentIndex - 1) + } else { + columnCount - (columnCount / 4) + if (segmentIndex == 0) { + -1 + } else { + 0 + } + } + } + + val x = (j1.toULong() * j1) shr 32 + val y = (referenceAreaSize.toULong() * x) shr 32 + val z = referenceAreaSize.toULong() - 1U - y + + val startPosition = if (iteration == 0) { + 0 + } else { + if (slice == 3) { + 0 + } else { + (slice + 1) * segmentLength + } + } + val absolutePosition = (startPosition + z.toInt()) % columnCount + + return Pair(l, absolutePosition) + } + + override fun derive(): UByteArray { + val blakeInput = parallelism.toUInt().toLittleEndianUByteArray() + + tagLength.toLittleEndianUByteArray() + + memorySize.toLittleEndianUByteArray() + + numberOfIterations.toUInt().toLittleEndianUByteArray() + + versionNumber.toLittleEndianUByteArray() + + argonType.typeId.toUInt().toLittleEndianUByteArray() + + password.size.toUInt().toLittleEndianUByteArray() + password + + salt.size.toUInt().toLittleEndianUByteArray() + salt + + key.size.toUInt().toLittleEndianUByteArray() + key + + associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData + val h0 = Blake2bStateless.digest( + blakeInput + ) + + //Compute B[i][0] + for (i in 0 until parallelism) { + matrix.setBlockAt(i, 0, + argonBlake2bArbitraryLenghtHash( + (h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(), + 1024U + ) + ) + } + + //Compute B[i][1] + for (i in 0 until parallelism) { + matrix.setBlockAt(i, 1, + argonBlake2bArbitraryLenghtHash( + (h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(), + 1024U + ) + ) + } + //Run all iterations over all lanes and all segments + executeArgonWithSingleThread() + + + val acc = ArgonBlock(matrix.getBlockAt(0, columnCount - 1)) + val accPointer = acc.getBlockPointer() + for (i in 1 until parallelism) { + accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1)) + } + //Hash the xored last blocks + val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength) + matrix.clearMatrix() + return hash + + + } + + private fun executeArgonWithSingleThread() { + for (iteration in 0 until numberOfIterations) { + for (slice in 0 until 4) { + for (lane in 0 until parallelism) { + val segmentPosition = SegmentPosition(iteration, lane, slice) + processSegment(segmentPosition) + } + } + } + } + + private fun processSegment(segmentPosition: SegmentPosition) { + val iteration = segmentPosition.iteration + val slice = segmentPosition.slice + val lane = segmentPosition.lane + + var addressBlock: ArgonBlockPointer? = null + var addressCounter = 1UL //Starts from 1 in each segment as defined by the spec + + //Generate initial segment address block + if (useIndependentAddressing) { + addressBlock = ArgonBlock().getBlockPointer() + addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter) + addressCounter++ + } + val startColumn = if (iteration == 0 && slice == 0) { + 2 + } else { + slice * segmentLength + } + + + for (column in startColumn until (slice + 1) * segmentLength) { + val segmentIndex = column - (slice * segmentLength) + //Each address block contains 128 addresses, and we use one per iteration, + //so once we do 128 iterations we need to calculate a new address block + if (useIndependentAddressing && segmentIndex != 0 && segmentIndex % 128 == 0) { + addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock!!, addressCounter) + addressCounter++ + } + val previousColumn = if (column == 0) { + columnCount - 1 + } else { + column - 1 + } + val (l, z) = computeReferenceBlockIndexes( + iteration, + slice, + lane, + column, + addressBlock + ) + + matrix.setBlockAt(lane, column, + compressionFunctionG( + matrix.getBlockPointer(lane, previousColumn), + matrix.getBlockPointer(l,z), + matrix.getBlockPointer(lane,column), + true + ).getAsUByteArray() + ) + } + + } + + +} diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt index 7bcf23f..5744082 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt @@ -18,10 +18,8 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2 -import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.BLOCK_SIZE -import com.ionspin.kotlin.crypto.util.arrayChunked -import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong import com.ionspin.kotlin.crypto.util.plus import com.ionspin.kotlin.crypto.util.rotateRight @@ -101,17 +99,17 @@ object Argon2Utils { internal fun argonBlake2bArbitraryLenghtHash(input: UByteArray, length: UInt): UByteArray { if (length <= 64U) { - return Blake2b.digest(inputMessage = length + input, hashLength = length.toInt()) + return Blake2bPure.digest(inputMessage = length + input, hashLength = length.toInt()) } //We can cast to int because UInt even if MAX_VALUE divided by 32 is guaranteed not to overflow val numberOf64ByteBlocks = (1U + ((length - 1U) / 32U) - 2U).toInt() // equivalent to ceil(length/32) - 2 val v = Array(numberOf64ByteBlocks) { ubyteArrayOf() } - v[0] = Blake2b.digest(length + input) + v[0] = Blake2bPure.digest(length + input) for (i in 1 until numberOf64ByteBlocks) { - v[i] = Blake2b.digest(v[i - 1]) + v[i] = Blake2bPure.digest(v[i - 1]) } val remainingPartOfInput = length.toInt() - numberOf64ByteBlocks * 32 - val vLast = Blake2b.digest(v[numberOf64ByteBlocks - 1], hashLength = remainingPartOfInput) + val vLast = Blake2bPure.digest(v[numberOf64ByteBlocks - 1], hashLength = remainingPartOfInput) val concat = (v.map { it.copyOfRange(0, 32) }) .plus(listOf(vLast)) diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/parallelization/Coroutines14.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/parallelization/Coroutines14.kt index 5ecff53..6a05cbb 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/parallelization/Coroutines14.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/parallelization/Coroutines14.kt @@ -16,11 +16,7 @@ package com.ionspin.kotlin.crypto.parallelization -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 -import kotlinx.coroutines.* -import kotlin.coroutines.CoroutineContext import kotlin.time.ExperimentalTime -import kotlin.time.measureTime /** * Created by Ugljesa Jovanovic diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbc.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt similarity index 90% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbc.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt index b2e492a..8b96fc5 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbc.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt @@ -17,13 +17,12 @@ package com.ionspin.kotlin.crypto.symmetric import com.ionspin.kotlin.crypto.SRNG -import com.ionspin.kotlin.crypto.util.chunked import com.ionspin.kotlin.crypto.util.xor /** * Advanced encryption standard with cipher block chaining and PKCS #5 * - * For bulk encryption/decryption use [AesCbc.encrypt] and [AesCbc.decrypt] + * For bulk encryption/decryption use [AesCbcPure.encrypt] and [AesCbcPure.decrypt] * * To get an instance of AesCbc and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor] * @@ -32,7 +31,7 @@ import com.ionspin.kotlin.crypto.util.xor * on 21-Sep-2019 */ @ExperimentalUnsignedTypes -class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) { +class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) { companion object { const val BLOCK_BYTES = 16 @@ -40,22 +39,22 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa * Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all * data call [encrypt] */ - fun createEncryptor(aesKey: AesKey) : AesCbc { - return AesCbc(aesKey, Mode.ENCRYPT) + fun createEncryptor(aesKey: AesKey) : AesCbcPure { + return AesCbcPure(aesKey, Mode.ENCRYPT) } /** * Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all * data call [decrypt] */ - fun createDecryptor(aesKey : AesKey) : AesCbc { - return AesCbc(aesKey, Mode.DECRYPT) + fun createDecryptor(aesKey : AesKey) : AesCbcPure { + return AesCbcPure(aesKey, Mode.DECRYPT) } /** * Bulk encryption, returns encrypted data and a random initialization vector */ fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitializationVector { - val aesCbc = AesCbc(aesKey, Mode.ENCRYPT) + val aesCbc = AesCbcPure(aesKey, Mode.ENCRYPT) aesCbc.addData(data) return aesCbc.encrypt() } @@ -64,7 +63,7 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa * Bulk decryption, returns decrypted data */ fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray { - val aesCbc = AesCbc(aesKey, Mode.DECRYPT, initialCounter) + val aesCbc = AesCbcPure(aesKey, Mode.DECRYPT, initialCounter) aesCbc.addData(data) return aesCbc.decrypt() } @@ -199,17 +198,17 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa Mode.ENCRYPT -> { currentOutput = if (currentOutput.isEmpty()) { println("IV: $initVector") - Aes.encrypt(aesKey, data xor initVector) + AesPure.encrypt(aesKey, data xor initVector) } else { - Aes.encrypt(aesKey, data xor currentOutput) + AesPure.encrypt(aesKey, data xor currentOutput) } currentOutput } Mode.DECRYPT -> { if (currentOutput.isEmpty()) { - currentOutput = Aes.decrypt(aesKey, data) xor initVector + currentOutput = AesPure.decrypt(aesKey, data) xor initVector } else { - currentOutput = Aes.decrypt(aesKey, data) xor previousEncrypted + currentOutput = AesPure.decrypt(aesKey, data) xor previousEncrypted } previousEncrypted = data currentOutput diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtr.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt similarity index 90% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtr.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt index 2410fae..eb18ed3 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtr.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt @@ -20,15 +20,14 @@ import com.ionspin.kotlin.bignum.Endianness import com.ionspin.kotlin.bignum.integer.BigInteger import com.ionspin.kotlin.bignum.modular.ModularBigInteger import com.ionspin.kotlin.crypto.SRNG -import com.ionspin.kotlin.crypto.util.chunked -import com.ionspin.kotlin.crypto.symmetric.AesCtr.Companion.encrypt +import com.ionspin.kotlin.crypto.symmetric.AesCtrPure.Companion.encrypt import com.ionspin.kotlin.crypto.util.xor /** * * Advanced encryption standard with counter mode * - * For bulk encryption/decryption use [AesCtr.encrypt] and [AesCtr.decrypt] + * For bulk encryption/decryption use [AesCtrPure.encrypt] and [AesCtrPure.decrypt] * * To get an instance of AesCtr and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor] * @@ -37,7 +36,7 @@ import com.ionspin.kotlin.crypto.util.xor * on 22-Sep-2019 */ @ExperimentalUnsignedTypes -class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) { +class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) { companion object { const val BLOCK_BYTES = 16 @@ -47,21 +46,21 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou * Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all * data call [encrypt] */ - fun createEncryptor(aesKey: AesKey) : AesCtr { - return AesCtr(aesKey, Mode.ENCRYPT) + fun createEncryptor(aesKey: AesKey) : AesCtrPure { + return AesCtrPure(aesKey, Mode.ENCRYPT) } /** * Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all * data call [decrypt] */ - fun createDecryptor(aesKey : AesKey) : AesCtr { - return AesCtr(aesKey, Mode.DECRYPT) + fun createDecryptor(aesKey : AesKey) : AesCtrPure { + return AesCtrPure(aesKey, Mode.DECRYPT) } /** * Bulk encryption, returns encrypted data and a random initial counter */ fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitialCounter { - val aesCtr = AesCtr(aesKey, Mode.ENCRYPT) + val aesCtr = AesCtrPure(aesKey, Mode.ENCRYPT) aesCtr.addData(data) return aesCtr.encrypt() } @@ -69,7 +68,7 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou * Bulk decryption, returns decrypted data */ fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray { - val aesCtr = AesCtr(aesKey, Mode.DECRYPT, initialCounter) + val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter) aesCtr.addData(data) return aesCtr.decrypt() } @@ -165,10 +164,10 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou val blockCountAsByteArray = blockCount.toUByteArray(Endianness.BIG).toUByteArray().expandCounterTo16Bytes() return when (mode) { Mode.ENCRYPT -> { - Aes.encrypt(aesKey, blockCountAsByteArray) xor data + AesPure.encrypt(aesKey, blockCountAsByteArray) xor data } Mode.DECRYPT -> { - Aes.encrypt(aesKey, blockCountAsByteArray) xor data + AesPure.encrypt(aesKey, blockCountAsByteArray) xor data } } diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Aes.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt similarity index 98% rename from multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Aes.kt rename to multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt index 371e872..b4f8807 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Aes.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt @@ -6,7 +6,7 @@ import com.ionspin.kotlin.crypto.util.flattenToUByteArray * Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 07/Sep/2019 */ @ExperimentalUnsignedTypes -internal class Aes internal constructor(val aesKey: AesKey, val input: UByteArray) { +internal class AesPure internal constructor(val aesKey: AesKey, val input: UByteArray) { companion object { private val debug = false @@ -57,11 +57,11 @@ internal class Aes internal constructor(val aesKey: AesKey, val input: UByteArra val rcon: UByteArray = ubyteArrayOf(0x8DU, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1BU, 0x36U) fun encrypt(aesKey: AesKey, input: UByteArray): UByteArray { - return Aes(aesKey, input).encrypt() + return AesPure(aesKey, input).encrypt() } fun decrypt(aesKey: AesKey, input: UByteArray): UByteArray { - return Aes(aesKey, input).decrypt() + return AesPure(aesKey, input).decrypt() } } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt index aeae03a..fc42829 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt @@ -16,10 +16,10 @@ package com.ionspin.kotlin.crypto -import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b -import com.ionspin.kotlin.crypto.hash.sha.Sha256 -import com.ionspin.kotlin.crypto.hash.sha.Sha512 -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure +import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure +import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType import com.ionspin.kotlin.crypto.util.testBlocking import kotlin.test.Test @@ -40,7 +40,7 @@ class ReadmeTest { @Test fun blake2bObjectExample() { val input = "abc" - val result = Blake2b.digest(input) + val result = Blake2bPure.digest(input) //@formatter:off val expectedResult = ubyteArrayOf( 0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U, @@ -59,7 +59,7 @@ class ReadmeTest { fun blake2bInstanceExample() { val test = "abc" val key = "key" - val blake2b = Blake2b(key) + val blake2b = Blake2bPure(key) blake2b.update(test) val result = blake2b.digest() @@ -79,7 +79,7 @@ class ReadmeTest { @Test fun sha256Example() { val input = "abc" - val result = Sha256.digest(inputString = input) + val result = Sha256Pure.digest(inputString = input) val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" assertTrue { result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) @@ -92,7 +92,7 @@ class ReadmeTest { @Test fun sha512Example() { val input = "abc" - val result = Sha512.digest(inputMessage = input.encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val result = Sha512Pure.digest(inputMessage = input.encodeToByteArray().map { it.toUByte() }.toUByteArray()) println(result.map { it.toString(16) }) val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" @@ -106,7 +106,7 @@ class ReadmeTest { @ExperimentalStdlibApi @Test fun sha256UpdatableExample() { - val sha256 = Sha256() + val sha256 = Sha256Pure() sha256.update("abc") val result = sha256.digest() val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" @@ -118,7 +118,7 @@ class ReadmeTest { @ExperimentalStdlibApi @Test fun sha512UpdatableExample() { - val sha512 = Sha512() + val sha512 = Sha512Pure() sha512.update("abc") val result = sha512.digest() val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + @@ -133,13 +133,13 @@ class ReadmeTest { @ExperimentalTime @Test fun argon2StringExample() = testBlocking { - val argon2Instance = Argon2( + val argon2Instance = Argon2Pure( password = "Password", salt = "RandomSalt", parallelism = 1, tagLength = 64U, requestedMemorySize = 4096U, - numberOfIterations = 100, + numberOfIterations = 2, key = "", associatedData = "", argonType = ArgonType.Argon2id @@ -147,7 +147,7 @@ class ReadmeTest { val time = measureTime { val tag = argon2Instance.derive() val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") - val expectedTagString = "27c61b6538ef9f4a1250f8712cac09fc4329969295f9440249437d38c1617a005c2702d76a8a59e4cda2dfba48e1132261dacdfd31296945906992ea32f1d06e" + val expectedTagString = "c19db7e22d1480702b943872c863baf8c43b53d0c3e2c782cd07bfc613eda159233bd821a945c239c5085c70257f7c93d8a809f81c4af367f4ad8f0443a8fc47" println("Tag: ${tagString}") assertEquals(tagString, expectedTagString) } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt index 1c08fcc..6d73b4b 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2KATTest.kt @@ -18,7 +18,7 @@ package com.ionspin.kotlin.crypto.hash.argon -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType import com.ionspin.kotlin.crypto.util.hexColumsPrint import kotlin.test.Test @@ -57,7 +57,7 @@ class Argon2KATTest { val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) - val digest = Argon2( + val digest = Argon2Pure( password, salt, parallelism.toInt(), @@ -98,7 +98,7 @@ class Argon2KATTest { val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) - val digest = Argon2( + val digest = Argon2Pure( password, salt, parallelism.toInt(), @@ -139,7 +139,7 @@ class Argon2KATTest { val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) - val digest = Argon2( + val digest = Argon2Pure( password, salt, parallelism.toInt(), diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt index 3c2f57d..c1dce9e 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2BTest.kt @@ -46,7 +46,7 @@ class Blake2BTest { "1234567890" + "1234567890" - val result = Blake2b.digest(test) + val result = Blake2bPure.digest(test) //Generated with b2sum 8.31 val expectedResult = ubyteArrayOf( //@formatter:off @@ -77,7 +77,7 @@ class Blake2BTest { "1234567890" - val result = Blake2b.digest(test) + val result = Blake2bPure.digest(test) val expectedResultString = "800bb78cd4da18995c8074713bb674" + "3cd94b2b6490a693fe4000ed00833b88b7b474d94af9cfed246b1b" + "4ce1935a76154d7ea7c410493557741d18ec3a08da75" @@ -93,7 +93,7 @@ class Blake2BTest { fun testDigest() { val test = "111111111122222222223333333333333" - val result = Blake2b.digest(test) + val result = Blake2bPure.digest(test) //Generated with b2sum 8.31 val expectedResult = ubyteArrayOf( //@formatter:off @@ -115,7 +115,7 @@ class Blake2BTest { val test = "abc" val key = "key" - val result = Blake2b.digest(test, key) + val result = Blake2bPure.digest(test, key) assertTrue { result.isNotEmpty() @@ -134,7 +134,7 @@ class Blake2BTest { fun testDigestFromRfc() { val test = "abc" - val result = Blake2b.digest(test) + val result = Blake2bPure.digest(test) //@formatter:off val expectedResult = ubyteArrayOf( @@ -272,7 +272,7 @@ class Blake2BTest { for (i in 0 until mixChain.size - 1) { val inputRound = mixChain[i] val round = i - val result = Blake2b.mixRound(inputRound, message, round) + val result = Blake2bPure.mixRound(inputRound, message, round) val expectedResult = mixChain[i + 1] assertTrue { result.contentEquals(expectedResult) @@ -286,7 +286,7 @@ class Blake2BTest { fun testInvalidHashLength() { val test = "1234567890" assertFailsWith(RuntimeException::class) { - val result = Blake2b.digest(inputString = test, hashLength = 65) + val result = Blake2bPure.digest(inputString = test, hashLength = 65) } } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt index 91ddf8f..fbf73cb 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bInstanceTest.kt @@ -42,7 +42,7 @@ class Blake2bInstanceTest { //@formatter:on ) - val blake2b = Blake2b() + val blake2b = Blake2bPure() for (i in 0 until updates) { blake2b.update(input) } @@ -60,7 +60,7 @@ class Blake2bInstanceTest { val expectedResult = "2F49AEB613E34E924E175A6AF2FAAD7BC78235F9C5E461C68FD5B47E".toLowerCase() + "E8E2FD2FB4C07D7E4A72404612D92899AF8A328F3B614ED77244B481151D40B11E32A4".toLowerCase() - val blake2b = Blake2b() + val blake2b = Blake2bPure() for (i in 0 until updates) { blake2b.update(input) } @@ -74,7 +74,7 @@ class Blake2bInstanceTest { fun testDigestWithKey() { val test = "abc" val key = "key" - val blake2b = Blake2b(key) + val blake2b = Blake2bPure(key) blake2b.update(test) val result = blake2b.digest() diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt index eae5b08..194fce5 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bKnowAnswerTests.kt @@ -37,7 +37,7 @@ class Blake2bKnowAnswerTests { fun knownAnswerTest() { kat.forEach { val parsedInput = it.input.chunked(2).map { it.toUByte(16) }.toUByteArray() - val result = Blake2b.digest( + val result = Blake2bPure.digest( inputMessage = parsedInput, key = it.key.chunked(2).map { it.toUByte(16) }.toUByteArray() ) @@ -53,7 +53,7 @@ class Blake2bKnowAnswerTests { kat.forEach { kat -> val parsedInput = kat.input.chunked(2).map { it.toUByte(16) }.toUByteArray() val chunkedInput = parsedInput.toList().chunked(128).map { it.toUByteArray() } - val blake2b = Blake2b(key = kat.key.chunked(2).map { it.toUByte(16) }.toUByteArray()) + val blake2b = Blake2bPure(key = kat.key.chunked(2).map { it.toUByte(16) }.toUByteArray()) chunkedInput.forEach { blake2b.update(it) } val result = blake2b.digest() assertTrue("KAT ${kat.input} \nkey: ${kat.key} \nexpected: {${kat.hash}") { diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt index 39b6c24..b82bc13 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Test.kt @@ -31,7 +31,7 @@ class Sha256Test { @Test fun testWellKnownValue() { - val result = Sha256.digest(inputString = "abc") + val result = Sha256Pure.digest(inputString = "abc") val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" assertTrue { result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray()) @@ -44,7 +44,7 @@ class Sha256Test { @Test fun testWellKnownDoubleBlock() { - val resultDoubleBlock = Sha256.digest(inputString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + val resultDoubleBlock = Sha256Pure.digest(inputString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") val expectedResultForDoubleBlock = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" assertTrue { resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) @@ -56,7 +56,7 @@ class Sha256Test { fun testWellKnown3() { //It's good that I'm consistent with names. - val resultDoubleBlock = Sha256.digest(inputString = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") + val resultDoubleBlock = Sha256Pure.digest(inputString = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) val expectedResultForDoubleBlock = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" assertTrue { @@ -71,7 +71,7 @@ class Sha256Test { for (i in 0 until 1000000) { inputBuilder.append("a") } - val resultDoubleBlock = Sha256.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val resultDoubleBlock = Sha256Pure.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) val expectedResultForDoubleBlock = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" assertTrue { resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt index bdb0db4..0bdcd0d 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256UpdateableTest.kt @@ -31,7 +31,7 @@ class Sha256UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownValue() { - val sha256 = Sha256() + val sha256 = Sha256Pure() sha256.update("abc") val result = sha256.digest() val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" @@ -43,7 +43,7 @@ class Sha256UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownDoubleBlock() { - val sha256 = Sha256() + val sha256 = Sha256Pure() sha256.update(data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") val resultDoubleBlock = sha256.digest() println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) @@ -56,7 +56,7 @@ class Sha256UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnown3() { //It's good that I'm consistent with names. - val sha256 = Sha256() + val sha256 = Sha256Pure() sha256.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") val resultDoubleBlock = sha256.digest() println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) @@ -69,7 +69,7 @@ class Sha256UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownLong() { - val sha256 = Sha256() + val sha256 = Sha256Pure() for (i in 0 until 10000) { sha256.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } @@ -84,7 +84,7 @@ class Sha256UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownLonger() { - val sha256 = Sha256() + val sha256 = Sha256Pure() for (i in 0 until 16_777_216) { if (i % 10000 == 0) { println("$i/16777216") diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt index c83c85d..910b36f 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Test.kt @@ -30,7 +30,7 @@ class Sha512Test { @Test fun testWellKnownValue() { - val result = Sha512.digest(inputMessage = "abc".encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val result = Sha512Pure.digest(inputMessage = "abc".encodeToByteArray().map { it.toUByte() }.toUByteArray()) println(result.map {it.toString(16)}) val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" @@ -45,7 +45,7 @@ class Sha512Test { @ExperimentalStdlibApi @Test fun testWellKnown3() { - val sha512 = Sha512() + val sha512 = Sha512Pure() sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") val resultDoubleBlock = sha512.digest() val expectedResultForDoubleBlock = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + @@ -62,7 +62,7 @@ class Sha512Test { for (i in 0 until 1000000) { inputBuilder.append("a") } - val resultDoubleBlock = Sha512.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) + val resultDoubleBlock = Sha512Pure.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray()) val expectedResultForDoubleBlock = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" assertTrue { resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray()) diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt index e2471d9..dc70563 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512UpdateableTest.kt @@ -29,7 +29,7 @@ class Sha512UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownValue() { - val sha512 = Sha512() + val sha512 = Sha512Pure() sha512.update("abc") val result = sha512.digest() val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + @@ -44,7 +44,7 @@ class Sha512UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownDoubleBlock() { - val sha512 = Sha512() + val sha512 = Sha512Pure() sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") val resultDoubleBlock = sha512.digest() println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = "")) @@ -58,7 +58,7 @@ class Sha512UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownLong() { - val sha512 = Sha512() + val sha512 = Sha512Pure() for (i in 0 until 10000) { sha512.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } @@ -73,7 +73,7 @@ class Sha512UpdatableTest { @ExperimentalStdlibApi @Test fun testWellKnownLonger() { - val sha512 = Sha512() + val sha512 = Sha512Pure() for (i in 0 until 16_777_216) { if (i % 10000 == 0) { println("$i/16777216") diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt index dc34234..0a560d1 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt @@ -16,7 +16,6 @@ package com.ionspin.kotlin.crypto.symmetric -import com.ionspin.kotlin.crypto.util.hexStringToUByteArray import com.ionspin.kotlin.crypto.util.hexStringToUByteArray import com.ionspin.kotlin.crypto.util.toHexString import kotlin.test.Test @@ -38,7 +37,7 @@ class AesCbcTest { val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" val aesCbc = - AesCbc(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray()) + AesCbcPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray()) aesCbc.addData(plaintext.hexStringToUByteArray()) val encrypted = aesCbc.encrypt() println("Encrypted: ${encrypted.encryptedData.toHexString()}") @@ -59,8 +58,8 @@ class AesCbcTest { val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" - val encryptedDataAndInitializationVector = AesCbc.encrypt(key, plainText.hexStringToUByteArray()) - val decrypted = AesCbc.decrypt( + val encryptedDataAndInitializationVector = AesCbcPure.encrypt(key, plainText.hexStringToUByteArray()) + val decrypted = AesCbcPure.decrypt( key, encryptedDataAndInitializationVector.encryptedData, encryptedDataAndInitializationVector.initilizationVector @@ -77,7 +76,7 @@ class AesCbcTest { val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" val aesCbc = - AesCbc(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray()) + AesCbcPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray()) aesCbc.addData(cipherText.hexStringToUByteArray()) val decrypted = aesCbc.decrypt() println("Decrypted: ${decrypted.toHexString()}") @@ -96,7 +95,7 @@ class AesCbcTest { val iv = "57f02a5c5339daeb0a2908a06ac6393f" val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" - val decrypted = AesCbc.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray()) + val decrypted = AesCbcPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray()) println("Decrypted: ${decrypted.toHexString()}") expectedPlainText == decrypted.toHexString() diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt index 4b140b5..5a07619 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrTest.kt @@ -38,7 +38,7 @@ class AesCtrTest { "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" val expectedCipherText = "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" - val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray()) + val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray()) aesCtr.addData( plaintext.hexStringToUByteArray() ) @@ -57,8 +57,8 @@ class AesCtrTest { val key = AesKey.Aes128Key(keyString) val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" - val encryptedDataAndInitializationVector = AesCtr.encrypt(key, plainText.hexStringToUByteArray()) - val decrypted = AesCtr.decrypt( + val encryptedDataAndInitializationVector = AesCtrPure.encrypt(key, plainText.hexStringToUByteArray()) + val decrypted = AesCtrPure.decrypt( key, encryptedDataAndInitializationVector.encryptedData, encryptedDataAndInitializationVector.initialCounter @@ -77,7 +77,7 @@ class AesCtrTest { "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" val expectedPlainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" - val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray()) + val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray()) aesCtr.addData(cipherText.hexStringToUByteArray()) val decrypted = aesCtr.decrypt() println("Decrypted: ${decrypted.toHexString()}") @@ -97,7 +97,7 @@ class AesCtrTest { "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" val expectedPlainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" - val decrypted = AesCtr.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray()) + val decrypted = AesCtrPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray()) println("Decrypted: ${decrypted.toHexString()}") expectedPlainText == decrypted.toHexString() } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt index ca3ef4f..4424296 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesTest.kt @@ -20,7 +20,7 @@ class AesTest { ubyteArrayOf(0U, 0U, 0U, 0U), ubyteArrayOf(0U, 0U, 0U, 0U) ) - val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput) fakeState.copyInto(aes.state) aes.subBytes() assertTrue { @@ -42,7 +42,7 @@ class AesTest { ubyteArrayOf(2U, 3U, 0U, 1U), ubyteArrayOf(3U, 0U, 1U, 2U) ) - val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput) fakeState.copyInto(aes.state) aes.shiftRows() assertTrue { @@ -56,7 +56,7 @@ class AesTest { assertTrue { val a = 0x57U val b = 0x83U - val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput) val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte()) c == 0xC1U.toUByte() } @@ -64,7 +64,7 @@ class AesTest { assertTrue { val a = 0x57U val b = 0x13U - val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput) val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte()) c == 0xFEU.toUByte() } @@ -89,7 +89,7 @@ class AesTest { ubyteArrayOf(0xbcU, 0x9dU, 0x01U, 0xc6U) ) - val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput) fakeState.copyInto(aes.state) aes.mixColumns() assertTrue { @@ -116,7 +116,7 @@ class AesTest { ).toTypedArray() - val aes = Aes(AesKey.Aes128Key(key), irrelevantInput) + val aes = AesPure(AesKey.Aes128Key(key), irrelevantInput) val result = aes.expandedKey.map { it.foldIndexed(0U) { index, acc, uByte -> acc + (uByte.toUInt() shl (24 - index * 8)) @@ -140,7 +140,7 @@ class AesTest { ).toTypedArray() - val aes = Aes(AesKey.Aes192Key(key), irrelevantInput) + val aes = AesPure(AesKey.Aes192Key(key), irrelevantInput) val result = aes.expandedKey.map { it.foldIndexed(0U) { index, acc, uByte -> acc + (uByte.toUInt() shl (24 - index * 8)) @@ -166,7 +166,7 @@ class AesTest { ).toTypedArray() - val aes = Aes(AesKey.Aes256Key(key), irrelevantInput) + val aes = AesPure(AesKey.Aes256Key(key), irrelevantInput) val result = aes.expandedKey.map { it.foldIndexed(0U) { index, acc, uByte -> acc + (uByte.toUInt() shl (24 - index * 8)) @@ -183,7 +183,7 @@ class AesTest { val key = "2b7e151628aed2a6abf7158809cf4f3c" val expectedResult = "3925841d02dc09fbdc118597196a0b32" - val aes = Aes(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) + val aes = AesPure(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) val result = aes.encrypt() assertTrue { result.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) @@ -197,12 +197,12 @@ class AesTest { val key = "2b7e151628aed2a6abf7158809cf4f3c" val expectedResult = "3925841d02dc09fbdc118597196a0b32" val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() - val aes = Aes(AesKey.Aes128Key(key), original) + val aes = AesPure(AesKey.Aes128Key(key), original) val encrypted = aes.encrypt() assertTrue { encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) } - val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted) + val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted) decrypted.contentEquals(original) } @@ -211,12 +211,12 @@ class AesTest { val key = "000102030405060708090a0b0c0d0e0f" val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a" val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() - val aes = Aes(AesKey.Aes128Key(key), original) + val aes = AesPure(AesKey.Aes128Key(key), original) val encrypted = aes.encrypt() assertTrue { encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) } - val aesDec = Aes(AesKey.Aes128Key(key), encrypted) + val aesDec = AesPure(AesKey.Aes128Key(key), encrypted) val decrypted = aesDec.decrypt() assertTrue { aesDec.expandedKey.contentDeepEquals(aes.expandedKey) @@ -229,11 +229,11 @@ class AesTest { val key = "000102030405060708090a0b0c0d0e0f" val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a" val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() - val encrypted = Aes.encrypt(AesKey.Aes128Key(key), original) + val encrypted = AesPure.encrypt(AesKey.Aes128Key(key), original) assertTrue { encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) } - val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted) + val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted) decrypted.contentEquals(original) } @@ -242,11 +242,11 @@ class AesTest { val key = "000102030405060708090a0b0c0d0e0f1011121314151617" val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191" val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() - val encrypted = Aes.encrypt(AesKey.Aes192Key(key), original) + val encrypted = AesPure.encrypt(AesKey.Aes192Key(key), original) assertTrue { encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) } - val decrypted = Aes.decrypt(AesKey.Aes192Key(key), encrypted) + val decrypted = AesPure.decrypt(AesKey.Aes192Key(key), encrypted) decrypted.contentEquals(original) } @@ -255,11 +255,11 @@ class AesTest { val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" val expectedResult = "8ea2b7ca516745bfeafc49904b496089" val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray() - val encrypted = Aes.encrypt(AesKey.Aes256Key(key), original) + val encrypted = AesPure.encrypt(AesKey.Aes256Key(key), original) assertTrue { encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()) } - val decrypted = Aes.decrypt(AesKey.Aes256Key(key), encrypted) + val decrypted = AesPure.decrypt(AesKey.Aes256Key(key), encrypted) decrypted.contentEquals(original) } } diff --git a/sample/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/sample/Runner.kt b/sample/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/sample/Runner.kt index c73d720..b696812 100644 --- a/sample/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/sample/Runner.kt +++ b/sample/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/sample/Runner.kt @@ -1,4 +1,4 @@ -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType import kotlin.time.ExperimentalTime import kotlin.time.measureTime @@ -7,7 +7,7 @@ import kotlin.time.measureTime @ExperimentalStdlibApi fun main() { println("Test") - val argon2Instance = Argon2( + val argon2Instance = Argon2Pure( password = "Password", salt = "RandomSalt", parallelism = 1, diff --git a/settings.gradle.kts b/settings.gradle.kts index 28fc9f8..07b9982 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,5 +35,6 @@ pluginManagement { enableFeaturePreview("GRADLE_METADATA") rootProject.name = "KotlinMultiplatformCrypto" include("multiplatform-crypto") +include("multiplatform-crypto-api") include("sample")