mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-20 14:01:22 +02:00
- Migrates NIP-49 from java to kotlin for kmp
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
// Copyright (C) 2011 - Will Glozer. All rights reserved.
|
||||
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc;
|
||||
|
||||
import static java.lang.System.arraycopy;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* An implementation of the Password-Based Key Derivation Function as specified
|
||||
* in RFC 2898.
|
||||
*
|
||||
* @author Will Glozer
|
||||
*/
|
||||
public class PBKDF {
|
||||
/**
|
||||
* Implementation of PBKDF2 (RFC2898).
|
||||
*
|
||||
* @param alg HMAC algorithm to use.
|
||||
* @param P Password.
|
||||
* @param S Salt.
|
||||
* @param c Iteration count.
|
||||
* @param dkLen Intended length, in octets, of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
public static byte[] pbkdf2(String alg, byte[] P, byte[] S, int c, int dkLen) throws GeneralSecurityException {
|
||||
Mac mac = Mac.getInstance(alg);
|
||||
mac.init(new SecretKeySpec(P, alg));
|
||||
byte[] DK = new byte[dkLen];
|
||||
pbkdf2(mac, S, c, DK, dkLen);
|
||||
return DK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of PBKDF2 (RFC2898).
|
||||
*
|
||||
* @param mac Pre-initialized {@link Mac} instance to use.
|
||||
* @param S Salt.
|
||||
* @param c Iteration count.
|
||||
* @param DK Byte array that derived key will be placed in.
|
||||
* @param dkLen Intended length, in octets, of the derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
|
||||
int hLen = mac.getMacLength();
|
||||
|
||||
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
|
||||
throw new GeneralSecurityException("Requested key length too long");
|
||||
}
|
||||
|
||||
byte[] U = new byte[hLen];
|
||||
byte[] T = new byte[hLen];
|
||||
byte[] block1 = new byte[S.length + 4];
|
||||
|
||||
int l = (int) Math.ceil((double) dkLen / hLen);
|
||||
int r = dkLen - (l - 1) * hLen;
|
||||
|
||||
arraycopy(S, 0, block1, 0, S.length);
|
||||
|
||||
for (int i = 1; i <= l; i++) {
|
||||
block1[S.length + 0] = (byte) (i >> 24 & 0xff);
|
||||
block1[S.length + 1] = (byte) (i >> 16 & 0xff);
|
||||
block1[S.length + 2] = (byte) (i >> 8 & 0xff);
|
||||
block1[S.length + 3] = (byte) (i >> 0 & 0xff);
|
||||
|
||||
mac.update(block1);
|
||||
mac.doFinal(U, 0);
|
||||
arraycopy(U, 0, T, 0, hLen);
|
||||
|
||||
for (int j = 1; j < c; j++) {
|
||||
mac.update(U);
|
||||
mac.doFinal(U, 0);
|
||||
|
||||
for (int k = 0; k < hLen; k++) {
|
||||
T[k] ^= U[k];
|
||||
}
|
||||
}
|
||||
|
||||
arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc
|
||||
|
||||
import java.security.GeneralSecurityException
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* An implementation of the Password-Based Key Derivation Function as specified
|
||||
* in RFC 2898.
|
||||
*
|
||||
* @author Will Glozer
|
||||
*/
|
||||
object PBKDF {
|
||||
/**
|
||||
* Implementation of PBKDF2 (RFC2898).
|
||||
*
|
||||
* @param alg HMAC algorithm to use.
|
||||
* @param password Password.
|
||||
* @param salt Salt.
|
||||
* @param iterationCount Iteration count.
|
||||
* @param dkLen Intended length, in octets, of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
@Throws(GeneralSecurityException::class)
|
||||
fun pbkdf2(
|
||||
alg: String,
|
||||
password: ByteArray,
|
||||
salt: ByteArray,
|
||||
iterationCount: Int,
|
||||
dkLen: Int,
|
||||
): ByteArray {
|
||||
val mac = Mac.getInstance(alg)
|
||||
mac.init(SecretKeySpec(password, alg))
|
||||
val destKey = ByteArray(dkLen)
|
||||
pbkdf2(mac, salt, iterationCount, destKey, dkLen)
|
||||
return destKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of PBKDF2 (RFC2898).
|
||||
*
|
||||
* @param mac Pre-initialized [Mac] instance to use.
|
||||
* @param salt Salt.
|
||||
* @param c Iteration count.
|
||||
* @param destKey Byte array that derived key will be placed in.
|
||||
* @param dkLen Intended length, in octets, of the derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(GeneralSecurityException::class)
|
||||
fun pbkdf2(
|
||||
mac: Mac,
|
||||
salt: ByteArray,
|
||||
c: Int,
|
||||
destKey: ByteArray,
|
||||
dkLen: Int,
|
||||
) {
|
||||
val hLen = mac.getMacLength()
|
||||
|
||||
if (dkLen > (2.0.pow(32.0) - 1) * hLen) {
|
||||
throw GeneralSecurityException("Requested key length too long")
|
||||
}
|
||||
|
||||
val uArray = ByteArray(hLen)
|
||||
val rArray = ByteArray(hLen)
|
||||
val block1 = ByteArray(salt.size + 4)
|
||||
|
||||
val l = ceil(dkLen.toDouble() / hLen).toInt()
|
||||
val r = dkLen - (l - 1) * hLen
|
||||
|
||||
System.arraycopy(salt, 0, block1, 0, salt.size)
|
||||
|
||||
for (i in 1..l) {
|
||||
block1[salt.size + 0] = (i shr 24 and 0xff).toByte()
|
||||
block1[salt.size + 1] = (i shr 16 and 0xff).toByte()
|
||||
block1[salt.size + 2] = (i shr 8 and 0xff).toByte()
|
||||
block1[salt.size + 3] = (i shr 0 and 0xff).toByte()
|
||||
|
||||
mac.update(block1)
|
||||
mac.doFinal(uArray, 0)
|
||||
System.arraycopy(uArray, 0, rArray, 0, hLen)
|
||||
|
||||
for (j in 1..<c) {
|
||||
mac.update(uArray)
|
||||
mac.doFinal(uArray, 0)
|
||||
|
||||
for (k in 0..<hLen) {
|
||||
rArray[k] = (rArray[k].toInt() xor uArray[k].toInt()).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(rArray, 0, destKey, (i - 1) * hLen, (if (i == l) r else hLen))
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,189 +0,0 @@
|
||||
// Copyright (C) 2011 - Will Glozer. All rights reserved.
|
||||
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc;
|
||||
|
||||
import static java.lang.Integer.MAX_VALUE;
|
||||
import static java.lang.System.arraycopy;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
|
||||
/**
|
||||
* An implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt</a>
|
||||
* key derivation function. This class will attempt to load a native library
|
||||
* containing the optimized C implementation from
|
||||
* <a href="http://www.tarsnap.com/scrypt.html">http://www.tarsnap.com/scrypt.html<a> and
|
||||
* fall back to the pure Java version if that fails.
|
||||
*
|
||||
* @author Will Glozer
|
||||
*/
|
||||
public class SCrypt {
|
||||
|
||||
/**
|
||||
* Implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
|
||||
*
|
||||
* @param passwd Password.
|
||||
* @param salt Salt.
|
||||
* @param N CPU cost parameter.
|
||||
* @param r Memory cost parameter.
|
||||
* @param p Parallelization parameter.
|
||||
* @param dkLen Intended length of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException when HMAC_SHA256 is not available.
|
||||
*/
|
||||
public static byte[] scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
|
||||
return scryptJ(passwd, salt, N, r, p, dkLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure Java implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
|
||||
*
|
||||
* @param passwd Password.
|
||||
* @param salt Salt.
|
||||
* @param N CPU cost parameter.
|
||||
* @param r Memory cost parameter.
|
||||
* @param p Parallelization parameter.
|
||||
* @param dkLen Intended length of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException when HMAC_SHA256 is not available.
|
||||
*/
|
||||
public static byte[] scryptJ(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
|
||||
if (N < 2 || (N & (N - 1)) != 0) throw new IllegalArgumentException("N must be a power of 2 greater than 1");
|
||||
|
||||
if (N > MAX_VALUE / 128 / r) throw new IllegalArgumentException("Parameter N is too large");
|
||||
if (r > MAX_VALUE / 128 / p) throw new IllegalArgumentException("Parameter r is too large");
|
||||
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeyOrEmptySpec(passwd, "HmacSHA256"));
|
||||
|
||||
byte[] DK = new byte[dkLen];
|
||||
|
||||
byte[] B = new byte[128 * r * p];
|
||||
byte[] XY = new byte[256 * r];
|
||||
byte[] V = new byte[128 * r * N];
|
||||
int i;
|
||||
|
||||
PBKDF.pbkdf2(mac, salt, 1, B, p * 128 * r);
|
||||
|
||||
for (i = 0; i < p; i++) {
|
||||
smix(B, i * 128 * r, r, N, V, XY);
|
||||
}
|
||||
|
||||
PBKDF.pbkdf2(mac, B, 1, DK, dkLen);
|
||||
|
||||
return DK;
|
||||
}
|
||||
|
||||
public static void smix(byte[] B, int Bi, int r, int N, byte[] V, byte[] XY) {
|
||||
int Xi = 0;
|
||||
int Yi = 128 * r;
|
||||
int i;
|
||||
|
||||
arraycopy(B, Bi, XY, Xi, 128 * r);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
arraycopy(XY, Xi, V, i * (128 * r), 128 * r);
|
||||
blockmix_salsa8(XY, Xi, Yi, r);
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
int j = integerify(XY, Xi, r) & (N - 1);
|
||||
blockxor(V, j * (128 * r), XY, Xi, 128 * r);
|
||||
blockmix_salsa8(XY, Xi, Yi, r);
|
||||
}
|
||||
|
||||
arraycopy(XY, Xi, B, Bi, 128 * r);
|
||||
}
|
||||
|
||||
public static void blockmix_salsa8(byte[] BY, int Bi, int Yi, int r) {
|
||||
byte[] X = new byte[64];
|
||||
int i;
|
||||
|
||||
arraycopy(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
|
||||
|
||||
for (i = 0; i < 2 * r; i++) {
|
||||
blockxor(BY, i * 64, X, 0, 64);
|
||||
salsa20_8(X);
|
||||
arraycopy(X, 0, BY, Yi + (i * 64), 64);
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
arraycopy(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
arraycopy(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
|
||||
}
|
||||
}
|
||||
|
||||
public static int R(int a, int b) {
|
||||
return (a << b) | (a >>> (32 - b));
|
||||
}
|
||||
|
||||
public static void salsa20_8(byte[] B) {
|
||||
int[] B32 = new int[16];
|
||||
int[] x = new int[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
B32[i] = (B[i * 4 + 0] & 0xff) << 0;
|
||||
B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
|
||||
B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
|
||||
B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
|
||||
}
|
||||
|
||||
arraycopy(B32, 0, x, 0, 16);
|
||||
|
||||
for (i = 8; i > 0; i -= 2) {
|
||||
x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
|
||||
x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
|
||||
x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
|
||||
x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
|
||||
x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
|
||||
x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
|
||||
x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
|
||||
x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
|
||||
x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
|
||||
x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
|
||||
x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
|
||||
x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
|
||||
x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
|
||||
x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
|
||||
x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
|
||||
x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
B[i * 4 + 0] = (byte) (B32[i] >> 0 & 0xff);
|
||||
B[i * 4 + 1] = (byte) (B32[i] >> 8 & 0xff);
|
||||
B[i * 4 + 2] = (byte) (B32[i] >> 16 & 0xff);
|
||||
B[i * 4 + 3] = (byte) (B32[i] >> 24 & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
public static void blockxor(byte[] S, int Si, byte[] D, int Di, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
D[Di + i] ^= S[Si + i];
|
||||
}
|
||||
}
|
||||
|
||||
public static int integerify(byte[] B, int Bi, int r) {
|
||||
int n;
|
||||
|
||||
Bi += (2 * r - 1) * 64;
|
||||
|
||||
n = (B[Bi + 0] & 0xff) << 0;
|
||||
n |= (B[Bi + 1] & 0xff) << 8;
|
||||
n |= (B[Bi + 2] & 0xff) << 16;
|
||||
n |= (B[Bi + 3] & 0xff) << 24;
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc
|
||||
|
||||
import com.vitorpamplona.quartz.nip49PrivKeyEnc.PBKDF.pbkdf2
|
||||
import java.security.GeneralSecurityException
|
||||
import javax.crypto.Mac
|
||||
|
||||
/**
|
||||
* An implementation of the [](http://www.tarsnap.com/scrypt/scrypt.pdf)scrypt
|
||||
* key derivation function. This class will attempt to load a native library
|
||||
* containing the optimized C implementation from
|
||||
* [http://www.tarsnap.com/scrypt.html<a> and
|
||||
* fall back to the pure Java version if that fails.
|
||||
*
|
||||
* @author Will Glozer
|
||||
</a>](http://www.tarsnap.com/scrypt.html) */
|
||||
object SCrypt {
|
||||
/**
|
||||
* Implementation of the [](http://www.tarsnap.com/scrypt/scrypt.pdf)scrypt KDF.
|
||||
*
|
||||
* @param passwd Password.
|
||||
* @param salt Salt.
|
||||
* @param n CPU cost parameter.
|
||||
* @param r Memory cost parameter.
|
||||
* @param p Parallelization parameter.
|
||||
* @param dkLen Intended length of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException when HMAC_SHA256 is not available.
|
||||
*/
|
||||
@Throws(GeneralSecurityException::class)
|
||||
fun scrypt(
|
||||
passwd: ByteArray,
|
||||
salt: ByteArray,
|
||||
n: Int,
|
||||
r: Int,
|
||||
p: Int,
|
||||
dkLen: Int,
|
||||
): ByteArray = scryptJ(passwd, salt, n, r, p, dkLen)
|
||||
|
||||
/**
|
||||
* Pure Java implementation of the [](http://www.tarsnap.com/scrypt/scrypt.pdf)scrypt KDF.
|
||||
*
|
||||
* @param passwd Password.
|
||||
* @param salt Salt.
|
||||
* @param n CPU cost parameter.
|
||||
* @param r Memory cost parameter.
|
||||
* @param p Parallelization parameter.
|
||||
* @param dkLen Intended length of the derived key.
|
||||
*
|
||||
* @return The derived key.
|
||||
*
|
||||
* @throws GeneralSecurityException when HMAC_SHA256 is not available.
|
||||
*/
|
||||
@Throws(GeneralSecurityException::class)
|
||||
fun scryptJ(
|
||||
passwd: ByteArray,
|
||||
salt: ByteArray,
|
||||
n: Int,
|
||||
r: Int,
|
||||
p: Int,
|
||||
dkLen: Int,
|
||||
): ByteArray {
|
||||
require(!(n < 2 || (n and (n - 1)) != 0)) { "N must be a power of 2 greater than 1" }
|
||||
|
||||
require(n <= Int.Companion.MAX_VALUE / 128 / r) { "Parameter N is too large" }
|
||||
require(r <= Int.Companion.MAX_VALUE / 128 / p) { "Parameter r is too large" }
|
||||
|
||||
val mac = Mac.getInstance("HmacSHA256")
|
||||
mac.init(SecretKeyOrEmptySpec(passwd, "HmacSHA256"))
|
||||
|
||||
val deskKey = ByteArray(dkLen)
|
||||
|
||||
val bArray = ByteArray(128 * r * p)
|
||||
val xyArray = ByteArray(256 * r)
|
||||
val vArray = ByteArray(128 * r * n)
|
||||
var i: Int
|
||||
|
||||
pbkdf2(mac, salt, 1, bArray, p * 128 * r)
|
||||
|
||||
i = 0
|
||||
while (i < p) {
|
||||
smix(bArray, i * 128 * r, r, n, vArray, xyArray)
|
||||
i++
|
||||
}
|
||||
|
||||
pbkdf2(mac, bArray, 1, deskKey, dkLen)
|
||||
|
||||
return deskKey
|
||||
}
|
||||
|
||||
fun smix(
|
||||
bArray: ByteArray,
|
||||
biArray: Int,
|
||||
r: Int,
|
||||
n: Int,
|
||||
vArray: ByteArray,
|
||||
xyArray: ByteArray,
|
||||
) {
|
||||
val xIndex = 0
|
||||
val yIndex = 128 * r
|
||||
var i: Int
|
||||
|
||||
System.arraycopy(bArray, biArray, xyArray, xIndex, 128 * r)
|
||||
|
||||
i = 0
|
||||
while (i < n) {
|
||||
System.arraycopy(xyArray, xIndex, vArray, i * (128 * r), 128 * r)
|
||||
blockmixSalsa8(xyArray, xIndex, yIndex, r)
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < n) {
|
||||
val j = integerify(xyArray, xIndex, r) and (n - 1)
|
||||
blockxor(vArray, j * (128 * r), xyArray, xIndex, 128 * r)
|
||||
blockmixSalsa8(xyArray, xIndex, yIndex, r)
|
||||
i++
|
||||
}
|
||||
|
||||
System.arraycopy(xyArray, xIndex, bArray, biArray, 128 * r)
|
||||
}
|
||||
|
||||
fun blockmixSalsa8(
|
||||
byArray: ByteArray,
|
||||
biArray: Int,
|
||||
yi: Int,
|
||||
r: Int,
|
||||
) {
|
||||
val xArray = ByteArray(64)
|
||||
var i: Int
|
||||
|
||||
System.arraycopy(byArray, biArray + (2 * r - 1) * 64, xArray, 0, 64)
|
||||
|
||||
i = 0
|
||||
while (i < 2 * r) {
|
||||
blockxor(byArray, i * 64, xArray, 0, 64)
|
||||
salsa20x8(xArray)
|
||||
System.arraycopy(xArray, 0, byArray, yi + (i * 64), 64)
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < r) {
|
||||
System.arraycopy(byArray, yi + (i * 2) * 64, byArray, biArray + (i * 64), 64)
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < r) {
|
||||
System.arraycopy(byArray, yi + (i * 2 + 1) * 64, byArray, biArray + (i + r) * 64, 64)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// NOT SURE IF THIS IS ACTUALLY A ROTATE. Ignore the name
|
||||
fun rotate(
|
||||
a: Int,
|
||||
b: Int,
|
||||
): Int = (a shl b) or (a ushr (32 - b))
|
||||
|
||||
fun salsa20x8(bArray: ByteArray) {
|
||||
val b32 = IntArray(16)
|
||||
val x = IntArray(16)
|
||||
var i: Int
|
||||
|
||||
i = 0
|
||||
while (i < 16) {
|
||||
b32[i] = (bArray[i * 4 + 0].toInt() and 0xff) shl 0
|
||||
b32[i] = b32[i] or ((bArray[i * 4 + 1].toInt() and 0xff) shl 8)
|
||||
b32[i] = b32[i] or ((bArray[i * 4 + 2].toInt() and 0xff) shl 16)
|
||||
b32[i] = b32[i] or ((bArray[i * 4 + 3].toInt() and 0xff) shl 24)
|
||||
i++
|
||||
}
|
||||
|
||||
System.arraycopy(b32, 0, x, 0, 16)
|
||||
|
||||
i = 8
|
||||
while (i > 0) {
|
||||
x[4] = x[4] xor rotate(x[0] + x[12], 7)
|
||||
x[8] = x[8] xor rotate(x[4] + x[0], 9)
|
||||
x[12] = x[12] xor rotate(x[8] + x[4], 13)
|
||||
x[0] = x[0] xor rotate(x[12] + x[8], 18)
|
||||
x[9] = x[9] xor rotate(x[5] + x[1], 7)
|
||||
x[13] = x[13] xor rotate(x[9] + x[5], 9)
|
||||
x[1] = x[1] xor rotate(x[13] + x[9], 13)
|
||||
x[5] = x[5] xor rotate(x[1] + x[13], 18)
|
||||
x[14] = x[14] xor rotate(x[10] + x[6], 7)
|
||||
x[2] = x[2] xor rotate(x[14] + x[10], 9)
|
||||
x[6] = x[6] xor rotate(x[2] + x[14], 13)
|
||||
x[10] = x[10] xor rotate(x[6] + x[2], 18)
|
||||
x[3] = x[3] xor rotate(x[15] + x[11], 7)
|
||||
x[7] = x[7] xor rotate(x[3] + x[15], 9)
|
||||
x[11] = x[11] xor rotate(x[7] + x[3], 13)
|
||||
x[15] = x[15] xor rotate(x[11] + x[7], 18)
|
||||
x[1] = x[1] xor rotate(x[0] + x[3], 7)
|
||||
x[2] = x[2] xor rotate(x[1] + x[0], 9)
|
||||
x[3] = x[3] xor rotate(x[2] + x[1], 13)
|
||||
x[0] = x[0] xor rotate(x[3] + x[2], 18)
|
||||
x[6] = x[6] xor rotate(x[5] + x[4], 7)
|
||||
x[7] = x[7] xor rotate(x[6] + x[5], 9)
|
||||
x[4] = x[4] xor rotate(x[7] + x[6], 13)
|
||||
x[5] = x[5] xor rotate(x[4] + x[7], 18)
|
||||
x[11] = x[11] xor rotate(x[10] + x[9], 7)
|
||||
x[8] = x[8] xor rotate(x[11] + x[10], 9)
|
||||
x[9] = x[9] xor rotate(x[8] + x[11], 13)
|
||||
x[10] = x[10] xor rotate(x[9] + x[8], 18)
|
||||
x[12] = x[12] xor rotate(x[15] + x[14], 7)
|
||||
x[13] = x[13] xor rotate(x[12] + x[15], 9)
|
||||
x[14] = x[14] xor rotate(x[13] + x[12], 13)
|
||||
x[15] = x[15] xor rotate(x[14] + x[13], 18)
|
||||
i -= 2
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < 16) {
|
||||
b32[i] = x[i] + b32[i]
|
||||
++i
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < 16) {
|
||||
bArray[i * 4 + 0] = (b32[i] shr 0 and 0xff).toByte()
|
||||
bArray[i * 4 + 1] = (b32[i] shr 8 and 0xff).toByte()
|
||||
bArray[i * 4 + 2] = (b32[i] shr 16 and 0xff).toByte()
|
||||
bArray[i * 4 + 3] = (b32[i] shr 24 and 0xff).toByte()
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
fun blockxor(
|
||||
sArray: ByteArray,
|
||||
si: Int,
|
||||
dArray: ByteArray,
|
||||
di: Int,
|
||||
len: Int,
|
||||
) {
|
||||
for (i in 0..<len) {
|
||||
dArray[di + i] = (dArray[di + i].toInt() xor sArray[si + i].toInt()).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
fun integerify(
|
||||
bArray: ByteArray,
|
||||
bi: Int,
|
||||
r: Int,
|
||||
): Int {
|
||||
var bIndex = bi
|
||||
var n: Int
|
||||
|
||||
bIndex += (2 * r - 1) * 64
|
||||
|
||||
n = (bArray[bIndex + 0].toInt() and 0xff) shl 0
|
||||
n = n or ((bArray[bIndex + 1].toInt() and 0xff) shl 8)
|
||||
n = n or ((bArray[bIndex + 2].toInt() and 0xff) shl 16)
|
||||
n = n or ((bArray[bIndex + 3].toInt() and 0xff) shl 24)
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
/**
|
||||
* This class specifies a secret key in a provider-independent fashion.
|
||||
*
|
||||
* <p>It can be used to construct a <code>SecretKey</code> from a byte array,
|
||||
* without having to go through a (provider-based)
|
||||
* <code>SecretKeyFactory</code>.
|
||||
*
|
||||
* <p>This class is only useful for raw secret keys that can be represented as
|
||||
* a byte array and have no key parameters associated with them, e.g., DES or
|
||||
* Triple DES keys.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
* @see javax.crypto.SecretKey
|
||||
* @see javax.crypto.SecretKeyFactory
|
||||
* @since 1.4
|
||||
*/
|
||||
public class SecretKeyOrEmptySpec implements KeySpec, SecretKey {
|
||||
|
||||
private static final long serialVersionUID = 6577238317307289933L;
|
||||
|
||||
/**
|
||||
* The secret key.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private byte[] key;
|
||||
|
||||
/**
|
||||
* The name of the algorithm associated with this key.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private String algorithm;
|
||||
|
||||
/**
|
||||
* Constructs a secret key from the given byte array.
|
||||
*
|
||||
* <p>This constructor does not check if the given bytes indeed specify a
|
||||
* secret key of the specified algorithm. For example, if the algorithm is
|
||||
* DES, this constructor does not check if <code>key</code> is 8 bytes
|
||||
* long, and also does not check for weak or semi-weak keys.
|
||||
* In order for those checks to be performed, an algorithm-specific
|
||||
* <i>key specification</i> class (in this case:
|
||||
* {@link DESKeySpec DESKeySpec})
|
||||
* should be used.
|
||||
*
|
||||
* @param key the key material of the secret key. The contents of
|
||||
* the array are copied to protect against subsequent modification.
|
||||
* @param algorithm the name of the secret-key algorithm to be associated
|
||||
* with the given key material.
|
||||
* See Appendix A in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
|
||||
* Java Cryptography Architecture Reference Guide</a>
|
||||
* for information about standard algorithm names.
|
||||
* @exception IllegalArgumentException if <code>algorithm</code>
|
||||
* is null or <code>key</code> is null or empty.
|
||||
*/
|
||||
public SecretKeyOrEmptySpec(byte[] key, String algorithm) {
|
||||
if (key == null || algorithm == null) {
|
||||
throw new IllegalArgumentException("Missing argument");
|
||||
}
|
||||
this.key = key.clone();
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a secret key from the given byte array, using the first
|
||||
* <code>len</code> bytes of <code>key</code>, starting at
|
||||
* <code>offset</code> inclusive.
|
||||
*
|
||||
* <p> The bytes that constitute the secret key are
|
||||
* those between <code>key[offset]</code> and
|
||||
* <code>key[offset+len-1]</code> inclusive.
|
||||
*
|
||||
* <p>This constructor does not check if the given bytes indeed specify a
|
||||
* secret key of the specified algorithm. For example, if the algorithm is
|
||||
* DES, this constructor does not check if <code>key</code> is 8 bytes
|
||||
* long, and also does not check for weak or semi-weak keys.
|
||||
* In order for those checks to be performed, an algorithm-specific key
|
||||
* specification class (in this case:
|
||||
* {@link DESKeySpec DESKeySpec})
|
||||
* must be used.
|
||||
*
|
||||
* @param key the key material of the secret key. The first
|
||||
* <code>len</code> bytes of the array beginning at
|
||||
* <code>offset</code> inclusive are copied to protect
|
||||
* against subsequent modification.
|
||||
* @param offset the offset in <code>key</code> where the key material
|
||||
* starts.
|
||||
* @param len the length of the key material.
|
||||
* @param algorithm the name of the secret-key algorithm to be associated
|
||||
* with the given key material.
|
||||
* See Appendix A in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
|
||||
* Java Cryptography Architecture Reference Guide</a>
|
||||
* for information about standard algorithm names.
|
||||
* @exception IllegalArgumentException if <code>algorithm</code>
|
||||
* is null or <code>key</code> is null, empty, or too short,
|
||||
* i.e. {@code key.length-offset<len}.
|
||||
* @exception ArrayIndexOutOfBoundsException is thrown if
|
||||
* <code>offset</code> or <code>len</code> index bytes outside the
|
||||
* <code>key</code>.
|
||||
*/
|
||||
public SecretKeyOrEmptySpec(byte[] key, int offset, int len, String algorithm) {
|
||||
if (key == null || algorithm == null) {
|
||||
throw new IllegalArgumentException("Missing argument");
|
||||
}
|
||||
if (key.length-offset < len) {
|
||||
throw new IllegalArgumentException
|
||||
("Invalid offset/length combination");
|
||||
}
|
||||
if (len < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("len is negative");
|
||||
}
|
||||
this.key = new byte[len];
|
||||
System.arraycopy(key, offset, this.key, 0, len);
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the algorithm associated with this secret key.
|
||||
*
|
||||
* @return the secret key algorithm.
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return this.algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the encoding format for this secret key.
|
||||
*
|
||||
* @return the string "RAW".
|
||||
*/
|
||||
public String getFormat() {
|
||||
return "RAW";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key material of this secret key.
|
||||
*
|
||||
* @return the key material. Returns a new array
|
||||
* each time this method is called.
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
return this.key.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a hash code value for the object.
|
||||
* Objects that are equal will also have the same hashcode.
|
||||
*/
|
||||
public int hashCode() {
|
||||
int retval = 0;
|
||||
for (int i = 1; i < this.key.length; i++) {
|
||||
retval += this.key[i] * i;
|
||||
}
|
||||
if (this.algorithm.equalsIgnoreCase("TripleDES"))
|
||||
return (retval ^= "desede".hashCode());
|
||||
else
|
||||
return (retval ^=
|
||||
this.algorithm.toLowerCase(Locale.ENGLISH).hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for equality between the specified object and this
|
||||
* object. Two SecretKeySpec objects are considered equal if
|
||||
* they are both SecretKey instances which have the
|
||||
* same case-insensitive algorithm name and key encoding.
|
||||
*
|
||||
* @param obj the object to test for equality with this object.
|
||||
*
|
||||
* @return true if the objects are considered equal, false if
|
||||
* <code>obj</code> is null or otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
|
||||
if (!(obj instanceof SecretKey))
|
||||
return false;
|
||||
|
||||
String thatAlg = ((SecretKey)obj).getAlgorithm();
|
||||
if (!(thatAlg.equalsIgnoreCase(this.algorithm))) {
|
||||
if ((!(thatAlg.equalsIgnoreCase("DESede"))
|
||||
|| !(this.algorithm.equalsIgnoreCase("TripleDES")))
|
||||
&& (!(thatAlg.equalsIgnoreCase("TripleDES"))
|
||||
|| !(this.algorithm.equalsIgnoreCase("DESede"))))
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] thatKey = ((SecretKey)obj).getEncoded();
|
||||
|
||||
return MessageDigest.isEqual(this.key, thatKey);
|
||||
}
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip49PrivKeyEnc
|
||||
|
||||
import java.security.MessageDigest
|
||||
import java.security.spec.KeySpec
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
/**
|
||||
* This class specifies a secret key in a provider-independent fashion.
|
||||
*
|
||||
*
|
||||
* It can be used to construct a `SecretKey` from a byte array,
|
||||
* without having to go through a (provider-based)
|
||||
* `SecretKeyFactory`.
|
||||
*
|
||||
*
|
||||
* This class is only useful for raw secret keys that can be represented as
|
||||
* a byte array and have no key parameters associated with them, e.g., DES or
|
||||
* Triple DES keys.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
* @see SecretKey
|
||||
*
|
||||
* @see javax.crypto.SecretKeyFactory
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
class SecretKeyOrEmptySpec :
|
||||
KeySpec,
|
||||
SecretKey {
|
||||
/**
|
||||
* The secret key.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private val key: ByteArray
|
||||
|
||||
/**
|
||||
* The name of the algorithm associated with this key.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private val algorithm: String
|
||||
|
||||
/**
|
||||
* Constructs a secret key from the given byte array.
|
||||
*
|
||||
*
|
||||
* This constructor does not check if the given bytes indeed specify a
|
||||
* secret key of the specified algorithm. For example, if the algorithm is
|
||||
* DES, this constructor does not check if `key` is 8 bytes
|
||||
* long, and also does not check for weak or semi-weak keys.
|
||||
* In order for those checks to be performed, an algorithm-specific
|
||||
* *key specification* class
|
||||
*
|
||||
* @param key the key material of the secret key. The contents of
|
||||
* the array are copied to protect against subsequent modification.
|
||||
* @param algorithm the name of the secret-key algorithm to be associated
|
||||
* with the given key material.
|
||||
* See Appendix A in the [
|
||||
* Java Cryptography Architecture Reference Guide]({@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA)
|
||||
* for information about standard algorithm names.
|
||||
* @exception IllegalArgumentException if `algorithm`
|
||||
* is null or `key` is null or empty.
|
||||
*/
|
||||
constructor(key: ByteArray, algorithm: String) {
|
||||
this.key = key.clone()
|
||||
this.algorithm = algorithm
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the algorithm associated with this secret key.
|
||||
*
|
||||
* @return the secret key algorithm.
|
||||
*/
|
||||
override fun getAlgorithm(): String = this.algorithm
|
||||
|
||||
/**
|
||||
* Returns the name of the encoding format for this secret key.
|
||||
*
|
||||
* @return the string "RAW".
|
||||
*/
|
||||
override fun getFormat(): String = "RAW"
|
||||
|
||||
/**
|
||||
* Returns the key material of this secret key.
|
||||
*
|
||||
* @return the key material. Returns a new array
|
||||
* each time this method is called.
|
||||
*/
|
||||
override fun getEncoded(): ByteArray = this.key.clone()
|
||||
|
||||
/**
|
||||
* Calculates a hash code value for the object.
|
||||
* Objects that are equal will also have the same hashcode.
|
||||
*/
|
||||
override fun hashCode(): Int {
|
||||
var retval = 0
|
||||
for (i in 1..<this.key.size) {
|
||||
retval += this.key[i] * i
|
||||
}
|
||||
if (this.algorithm.equals("TripleDES", ignoreCase = true)) {
|
||||
return (
|
||||
"desede"
|
||||
.hashCode()
|
||||
.let {
|
||||
retval = retval xor it
|
||||
retval
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
this.algorithm.lowercase().hashCode().let {
|
||||
retval = retval xor it
|
||||
retval
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for equality between the specified object and this
|
||||
* object. Two SecretKeySpec objects are considered equal if
|
||||
* they are both SecretKey instances which have the
|
||||
* same case-insensitive algorithm name and key encoding.
|
||||
*
|
||||
* @param other the object to test for equality with this object.
|
||||
*
|
||||
* @return true if the objects are considered equal, false if
|
||||
* `obj` is null or otherwise.
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
if (other !is SecretKey) return false
|
||||
|
||||
val thatAlg = other.algorithm
|
||||
if (!(thatAlg.equals(this.algorithm, ignoreCase = true))) {
|
||||
if ((
|
||||
!(thatAlg.equals("DESede", ignoreCase = true)) ||
|
||||
!(this.algorithm.equals("TripleDES", ignoreCase = true))
|
||||
) &&
|
||||
(
|
||||
!(thatAlg.equals("TripleDES", ignoreCase = true)) ||
|
||||
!(this.algorithm.equals("DESede", ignoreCase = true))
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val thatKey = other.encoded
|
||||
|
||||
return MessageDigest.isEqual(this.key, thatKey)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val serialVersionUID = 6577238317307289933L
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user