wolfcrypt-jni/src/main/java/com/wolfssl/wolfcrypt/Dh.java

358 lines
10 KiB
Java

/* Dh.java
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl.wolfcrypt;
/**
* Wrapper for the native WolfCrypt DH implementation.
*/
public class Dh extends NativeStruct {
private WolfCryptState state = WolfCryptState.UNINITIALIZED;
private byte[] privateKey = null;
private byte[] publicKey = null;
private int pSize = 0;
/* DH parameters to init with, will reset to null after initialized */
private byte[] paramP = null;
private byte[] paramG = null;
/** Lock around object state */
protected final Object stateLock = new Object();
/**
* Create new Dh object.
*
* @throws WolfCryptException if DH has not been compiled into native
* wolfCrypt library.
*/
public Dh() {
if (!FeatureDetect.DhEnabled()) {
throw new WolfCryptException(
WolfCryptError.NOT_COMPILED_IN.getCode());
}
/* Internal state is initialized on first use */
}
/**
* Create new Dh object
*
* @param p DH p parameter
* @param g DH g parameter
*
* @throws WolfCryptException if DH has not been compiled into native
* wolfCrypt library.
*/
public Dh(byte[] p, byte[] g) {
if (!FeatureDetect.DhEnabled()) {
throw new WolfCryptException(
WolfCryptError.NOT_COMPILED_IN.getCode());
}
/* Internal state is initialized on first use */
this.paramP = p.clone();
this.paramG = g.clone();
}
@Override
public synchronized void releaseNativeStruct() {
synchronized (stateLock) {
if ((state != WolfCryptState.UNINITIALIZED) &&
(state != WolfCryptState.RELEASED)) {
synchronized (pointerLock) {
wc_FreeDhKey();
}
setPrivateKey(new byte[0]);
setPublicKey(new byte[0]);
super.releaseNativeStruct();
state = WolfCryptState.RELEASED;
}
}
}
private native long mallocNativeStruct_internal() throws OutOfMemoryError;
private native void wc_InitDhKey();
private native void wc_FreeDhKey();
private native void wc_DhSetKey(byte[] p, byte[] g);
private native void wc_DhGenerateKeyPair(Rng rng, int pSize);
private native byte[] wc_DhAgree(byte[] priv, byte[] pub);
/**
* Malloc native JNI DH structure
*
* @return native allocated pointer
*
* @throws OutOfMemoryError when malloc fails with memory error
*/
protected long mallocNativeStruct()
throws OutOfMemoryError {
synchronized (pointerLock) {
return mallocNativeStruct_internal();
}
}
/**
* Internal helper method to initialize object if/when needed.
*
* @throws IllegalStateException on failure to initialize properly, or
* if releaseNativeStruct() has been called and object has been
* released
*/
private synchronized void checkStateAndInitialize()
throws IllegalStateException {
synchronized (stateLock) {
if (state == WolfCryptState.RELEASED) {
throw new IllegalStateException("Object has been released");
}
if (state == WolfCryptState.UNINITIALIZED) {
init();
if (this.paramP != null && this.paramG != null) {
setParams(this.paramP, this.paramG);
this.paramP = null;
this.paramG = null;
}
}
if (state == WolfCryptState.UNINITIALIZED) {
throw new IllegalStateException("Failed to initialize Object");
}
}
}
/**
* Initialize Dh object.
*/
private void init() {
synchronized (pointerLock) {
/* Allocate native struct pointer from NativeStruct */
initNativeStruct();
wc_InitDhKey();
}
state = WolfCryptState.INITIALIZED;
}
/**
* Set private key
*
* @param priv private key array
*
* @throws IllegalStateException if object fails to initialize, or if
* releaseNativeStruct() has been called and object has been
* released.
*/
public synchronized void setPrivateKey(byte[] priv)
throws IllegalStateException {
checkStateAndInitialize();
if (privateKey != null) {
for (int i = 0; i < privateKey.length; i++) {
privateKey[i] = 0;
}
}
privateKey = priv.clone();
}
/**
* Set public key
*
* @param pub public key array
*
* @throws IllegalStateException if object fails to initialize, or if
* releaseNativeStruct() has been called and object has been
* released.
*/
public synchronized void setPublicKey(byte[] pub) {
checkStateAndInitialize();
if (publicKey != null) {
for (int i = 0; i < publicKey.length; i++) {
publicKey[i] = 0;
}
}
publicKey = pub.clone();
}
/**
* Get public key
*
* @return public key as byte array
*/
public synchronized byte[] getPublicKey() {
return publicKey;
}
/**
* Get private key
*
* @return private key as byte array
*/
public synchronized byte[] getPrivateKey() {
return privateKey;
}
/**
* Set DH parameters
*
* @param p DH p parameter
* @param g DH g parameter
*
* @throws WolfCryptException if native operation fails
* @throws IllegalStateException if object fails to initialize, or if
* releaseNativeStruct() has been called and object has been
* released.
*/
public synchronized void setParams(byte[] p, byte[] g)
throws WolfCryptException, IllegalStateException {
checkStateAndInitialize();
synchronized (pointerLock) {
wc_DhSetKey(p, g);
}
this.pSize = p.length;
state = WolfCryptState.READY;
}
/**
* Generate DH key inside object
*
* @param rng initialized Rng object
*
* @throws WolfCryptException if native operation fails
* @throws IllegalStateException if object already has a key, if object
* fails to initialize, or if releaseNativeStruct() has been
* called and object has been released.
*/
public synchronized void makeKey(Rng rng)
throws WolfCryptException, IllegalStateException {
checkStateAndInitialize();
if (privateKey == null) {
/* use size of P to allocate key buffer size */
synchronized (pointerLock) {
wc_DhGenerateKeyPair(rng, this.pSize);
}
} else {
throw new IllegalStateException("Object already has a key");
}
}
/**
* Generate DH shared secret using private and public key stored in
* this object.
*
* @return shared secret as byte array
*
* @throws WolfCryptException if native operation fails
* @throws IllegalStateException if object has no stored private and
* public keys, if object fails to initialize, or if
* releaseNativeStruct() has been called and object has been
* released.
*/
public synchronized byte[] makeSharedSecret()
throws WolfCryptException, IllegalStateException {
byte[] publicKey = null;
checkStateAndInitialize();
publicKey = getPublicKey();
if (publicKey == null) {
throw new IllegalStateException(
"Dh object has no public key");
}
return makeSharedSecret(publicKey);
}
/**
* Generate DH shared secret
*
* @param pubKey public key to use for secret generation
*
* @return shared secret as byte array
*
* @throws WolfCryptException if native operation fails
* @throws IllegalStateException if object has no key, if object
* fails to initialize, or if releaseNativeStruct() has been
* called and object has been released.
*/
public synchronized byte[] makeSharedSecret(Dh pubKey)
throws WolfCryptException, IllegalStateException {
if (pubKey == null) {
throw new IllegalStateException(
"Provided public key is null");
}
checkStateAndInitialize();
return makeSharedSecret(pubKey.getPublicKey());
}
/**
* Generate DH shared secret using internal private key and
* externally-provided public key as byte array.
*
* @param pubKey public key to use for secret generation
*
* @return shared secret as byte array
*
* @throws WolfCryptException if native operation fails
* @throws IllegalStateException if object has no key, if object
* fails to initialize, or if releaseNativeStruct() has been
* called and object has been released.
*/
public synchronized byte[] makeSharedSecret(byte[] pubKey)
throws WolfCryptException, IllegalStateException {
if (pubKey == null) {
throw new IllegalStateException(
"Provided public key is null");
}
if (this.privateKey == null) {
throw new IllegalStateException(
"Dh object has no private key");
}
checkStateAndInitialize();
synchronized (pointerLock) {
return wc_DhAgree(this.privateKey, pubKey);
}
}
}