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 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. - * - *
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 (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
- * Java Cryptography Architecture Reference Guide
- * for information about standard algorithm names.
- * @exception IllegalArgumentException if algorithm
- * is null or key
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
- * len
bytes of key
, starting at
- * offset
inclusive.
- *
- *
The bytes that constitute the secret key are
- * those between key[offset]
and
- * key[offset+len-1]
inclusive.
- *
- *
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 (in this case:
- * {@link DESKeySpec DESKeySpec})
- * must be used.
- *
- * @param key the key material of the secret key. The first
- * len
bytes of the array beginning at
- * offset
inclusive are copied to protect
- * against subsequent modification.
- * @param offset the offset in key
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
- * Java Cryptography Architecture Reference Guide
- * for information about standard algorithm names.
- * @exception IllegalArgumentException if algorithm
- * is null or key
is null, empty, or too short,
- * i.e. {@code key.length-offsetlen
index bytes outside the
- * key
.
- */
- 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
- * obj
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);
- }
-}
diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt
new file mode 100644
index 000000000..a5cc12e25
--- /dev/null
+++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt
@@ -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..