All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.hashgraph.sdk.PrivateKey Maven / Gradle / Ivy

The newest version!
/*-
 *
 * Hedera Java SDK
 *
 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.hedera.hashgraph.sdk;

import com.google.errorprone.annotations.Var;
import com.hedera.hashgraph.sdk.proto.SignedTransaction;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.sec.ECPrivateKey;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.math.ec.rfc8032.Ed25519;
import org.bouncycastle.util.encoders.Hex;

import javax.annotation.Nonnegative;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Arrays;

/**
 * A private key on the Hedera™ network.
 */
public abstract class PrivateKey extends Key {
    /**
     * The public key derived from the private key
     */
    @Nullable
    protected PublicKey publicKey = null; // Cache the derivation of the public key

    /**
     * Generates a new Ed25519 private key.
     *
     * @deprecated use {@link #generateED25519()} or {@link #generateECDSA()} instead
     *
     * @return the new Ed25519 private key.
     */
    public static PrivateKey generate() {
        return generateED25519();
    }

    /**
     * Extract the new ED25519 private key.
     *
     * @return                          the new ED25519 private key
     */
    public static PrivateKey generateED25519() {
        return PrivateKeyED25519.generateInternal();
    }

    /**
     * Extract the new ECDSA private key.
     *
     * @return                          the new ECDSA private key
     */
    public static PrivateKey generateECDSA() {
        return PrivateKeyECDSA.generateInternal();
    }

    /**
     * Extract the ED25519 private key from a seed.
     *
     * @param seed  the seed
     * @return      the ED25519 private key
     */
    public static PrivateKey fromSeedED25519(byte[] seed) {
        return PrivateKeyED25519.fromSeed(seed);
    }

    /**
     * Extract the ECDSA private key from a seed.
     *
     * @param seed  the seed
     * @return      the ECDSA private key
     */
    public static PrivateKey fromSeedECDSAsecp256k1(byte[] seed) {
        return PrivateKeyECDSA.fromSeed(seed);
    }

    /**
     * @deprecated use {@link Mnemonic#toStandardEd25519PrivateKey(String, int)} ()} or {@link Mnemonic#toStandardECDSAsecp256k1PrivateKey(String, int)} (String, int)} instead
     * This function uses incomplete and the key should not be used directly.
     * 

* Recover a private key from a generated mnemonic phrase and a passphrase. *

* This is not compatible with the phrases generated by the Android and iOS wallets; * use the no-passphrase version instead. * * @param mnemonic the mnemonic phrase which should be a 24 byte list of words. * @param passphrase the passphrase used to protect the mnemonic (not used in the * mobile wallets, use {@link #fromMnemonic(Mnemonic)} instead.) * @return the recovered key; use {@link #derive(int)} to get a key for an account index (0 * for default account) */ @Deprecated public static PrivateKey fromMnemonic(Mnemonic mnemonic, String passphrase) { var seed = mnemonic.toSeed(passphrase); @Var PrivateKey derivedKey = fromSeedED25519(seed); // BIP-44 path with the Hedera Hbar coin-type (omitting key index) // we pre-derive most of the path as the mobile wallets don't expose more than the index // https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki // https://github.com/satoshilabs/slips/blob/master/slip-0044.md for (int index : new int[]{44, 3030, 0, 0}) { derivedKey = derivedKey.derive(index); } return derivedKey; } /** * @deprecated use {@link Mnemonic#toStandardEd25519PrivateKey(String, int)} ()} or {@link Mnemonic#toStandardECDSAsecp256k1PrivateKey(String, int)} (String, int)} instead * Recover a private key from a mnemonic phrase compatible with the iOS and Android wallets. *

* An overload of {@link #fromMnemonic(Mnemonic, String)} which uses an empty string for the * passphrase. * * @param mnemonic the mnemonic phrase which should be a 24 byte list of words. * @return the recovered key; use {@link #derive(int)} to get a key for an account index (0 * for default account) */ @Deprecated public static PrivateKey fromMnemonic(Mnemonic mnemonic) { return fromMnemonic(mnemonic, ""); } /** * Retrieve a private key from a string. * * @param privateKey string representing a private key * @return the private key */ public static PrivateKey fromString(String privateKey) { return fromBytes(Hex.decode(privateKey.startsWith("0x") ? privateKey.substring(2) : privateKey)); } /** * Retrieve a private key from a DER encoded string. * * @param privateKey DER encoded string representing a private key * @return the private key */ public static PrivateKey fromStringDER(String privateKey) { return fromBytesDER(Hex.decode(privateKey)); } /** * Retrieve a private key from an ED25519 encoded string. * * @param privateKey ED25519 encoded string representing a private key * @return the private key */ public static PrivateKey fromStringED25519(String privateKey) { return fromBytesED25519(Hex.decode(privateKey)); } /** * Retrieve a private key from an ECDSA encoded string. * * @param privateKey ECDSA encoded string representing a private key * @return the private key */ public static PrivateKey fromStringECDSA(String privateKey) { return fromBytesECDSA(Hex.decode(privateKey)); } /** * Retrieve a private key from a byte array. * * @param privateKey byte array representing a private key * @return the private key */ public static PrivateKey fromBytes(byte[] privateKey) { if ((privateKey.length == Ed25519.SECRET_KEY_SIZE) || (privateKey.length == Ed25519.SECRET_KEY_SIZE + Ed25519.PUBLIC_KEY_SIZE)) { // If this is a 32 or 64 byte string, assume an Ed25519 private key return new PrivateKeyED25519(Arrays.copyOfRange(privateKey, 0, Ed25519.SECRET_KEY_SIZE), null); } // Assume a DER-encoded private key descriptor return fromBytesDER(privateKey); } /** * Retrieve a private key from an ED25519 encoded byte array. * * @param privateKey ED25519 encoded byte array representing a private key * @return the private key */ public static PrivateKey fromBytesED25519(byte[] privateKey) { return PrivateKeyED25519.fromBytesInternal(privateKey); } /** * Retrieve a private key from an ECDSA encoded byte array. * * @param privateKey ECDSA encoded byte array representing a private key * @return the private key */ public static PrivateKey fromBytesECDSA(byte[] privateKey) { return PrivateKeyECDSA.fromBytesInternal(privateKey); } /** * Retrieve a private key from a DER encoded byte array. * * @param privateKey DER encoded byte array representing a private key * @return the private key */ public static PrivateKey fromBytesDER(byte[] privateKey) { try { return fromPrivateKeyInfo(PrivateKeyInfo.getInstance(privateKey)); } catch (ClassCastException | IllegalArgumentException e) { return PrivateKeyECDSA.fromECPrivateKeyInternal(ECPrivateKey.getInstance(privateKey)); } } /** * Retrieve a private key from a private key info object. * * @param privateKeyInfo private key info object * @return the private key */ private static PrivateKey fromPrivateKeyInfo(PrivateKeyInfo privateKeyInfo) { if (privateKeyInfo.getPrivateKeyAlgorithm().equals(new AlgorithmIdentifier(ID_ED25519))) { return PrivateKeyED25519.fromPrivateKeyInfoInternal(privateKeyInfo); } else { // assume ECDSA return PrivateKeyECDSA.fromPrivateKeyInfoInternal(privateKeyInfo); } } /** * Parse a private key from a PEM encoded reader. *

* This will read the first "PRIVATE KEY" section in the stream as an Ed25519 private key. * * @param pemFile The Reader containing the pem file * @return {@link com.hedera.hashgraph.sdk.PrivateKey} * @throws IOException if one occurred while reading. * @throws BadKeyException if no "PRIVATE KEY" section was found or the key was not an Ed25519 * private key. */ public static PrivateKey readPem(Reader pemFile) throws IOException { return readPem(pemFile, null); } /** * Parse a private key from a PEM encoded stream. The key may be encrypted, e.g. if it was * generated by OpenSSL. *

* If password is not null or empty, this will read the first "ENCRYPTED PRIVATE KEY" * section in the stream as a PKCS#8 * EncryptedPrivateKeyInfo structure * and use that algorithm to decrypt the private key with the given password. Otherwise, * it will read the first "PRIVATE KEY" section as DER-encoded Ed25519 private key. *

* To generate an encrypted private key with OpenSSL, open a terminal and enter the following * command: *

     * {@code openssl genpkey -algorithm ed25519 -aes-128-cbc > key.pem}
     * 
*

* Then enter your password of choice when prompted. When the command completes, your encrypted * key will be saved as `key.pem` in the working directory of your terminal. * * @param pemFile the PEM encoded file * @param password the password to decrypt the PEM file; if null or empty, no decryption is performed. * @return {@link com.hedera.hashgraph.sdk.PrivateKey} * @throws IOException if one occurred while reading the PEM file * @throws BadKeyException if no "ENCRYPTED PRIVATE KEY" or "PRIVATE KEY" section was found, * if the passphrase is wrong or the key was not an Ed25519 private key. */ public static PrivateKey readPem(Reader pemFile, @Nullable String password) throws IOException { return fromPrivateKeyInfo(Pem.readPrivateKey(pemFile, password)); } /** * Parse a private key from a PEM encoded string. * * @param pemEncoded The String containing the pem * @return {@link com.hedera.hashgraph.sdk.PrivateKey} * @throws IOException if the PEM string was improperly encoded * @throws BadKeyException if no "PRIVATE KEY" section was found or the key was not an Ed25519 * private key. * @see #readPem(Reader) */ public static PrivateKey fromPem(String pemEncoded) throws IOException { return readPem(new StringReader(pemEncoded)); } /** * Parse a private key from a PEM encoded string. *

* The private key may be encrypted, e.g. if it was generated by OpenSSL. * * @param encodedPem the encoded PEM string * @param password the password to decrypt the PEM file; if null or empty, no decryption is performed. * @return {@link com.hedera.hashgraph.sdk.PrivateKey} * @throws IOException if the PEM string was improperly encoded * @throws BadKeyException if no "ENCRYPTED PRIVATE KEY" or "PRIVATE KEY" section was found, * if the passphrase is wrong or the key was not an Ed25519 private key. * @see #readPem(Reader, String) */ public static PrivateKey fromPem(String encodedPem, @Nullable String password) throws IOException { return readPem(new StringReader(encodedPem), password); } /** * Derive a child key based on the index. * * @param index the index * @return the derived child key */ public PrivateKey legacyDerive(int index) { return legacyDerive((long) index); } /** * Derive a child key based on the index. * * @param index the index * @return the derived child key */ public abstract PrivateKey legacyDerive(long index); /** * Check if this private key supports derivation. *

* This is currently only the case if this private key was created from a mnemonic. * * @return boolean */ public abstract boolean isDerivable(); /** * Given a wallet/account index, derive a child key compatible with the iOS and Android wallets. *

* Use index 0 for the default account. * * @param index the wallet/account index of the account, 0 for the default account. * @return the derived key * @throws IllegalStateException if this key does not support derivation. * @see #isDerivable() */ public abstract PrivateKey derive(int index); /** * Derive a public key from this private key. * *

The public key can be freely given and used by other parties to verify the signatures * generated by this private key. * * @return the corresponding public key for this private key. */ public abstract PublicKey getPublicKey(); /** * Sign a message with this private key. * * @param message The array of bytes to sign with * @return the signature of the message. */ public abstract byte[] sign(byte[] message); /** * Sign a transaction. * * @param transaction the transaction * @return the signed transaction */ public byte[] signTransaction(Transaction transaction) { transaction.requireOneNodeAccountId(); if (!transaction.isFrozen()) { transaction.freeze(); } var builder = (SignedTransaction.Builder) transaction.innerSignedTransactions.get(0); var signature = sign(builder.getBodyBytes().toByteArray()); transaction.addSignature(getPublicKey(), signature); return signature; } @Override public abstract byte[] toBytes(); /** * Extract the byte array encoded as DER. * * @return the byte array encoded as DER */ public abstract byte[] toBytesDER(); /** * Extract the raw byte array. * * @return the raw byte array */ public abstract byte[] toBytesRaw(); @Override public String toString() { return toStringDER(); } /** * Extract the DER encoded hex string. * * @return the DER encoded hex string */ public String toStringDER() { return Hex.toHexString(toBytesDER()); } /** * Extract the raw hex string. * * @return the raw hex string */ public String toStringRaw() { return Hex.toHexString(toBytesRaw()); } /** * Retrieve the account id. * * @param shard the shard * @param realm the realm * @return the account id */ public AccountId toAccountId(@Nonnegative long shard, @Nonnegative long realm) { return getPublicKey().toAccountId(shard, realm); } @Override com.hedera.hashgraph.sdk.proto.Key toProtobufKey() { // Forward to the corresponding public key. return getPublicKey().toProtobufKey(); } /** * Are we an ED25519 key? * * @return are we an ED25519 key */ public abstract boolean isED25519(); /** * Are we an ECDSA key? * * @return are we an ECDSA key */ public abstract boolean isECDSA(); /** * Get the chain code of the key * * @return the chainCode */ public abstract KeyParameter getChainCode(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy