164 lines
5.7 KiB
Java
164 lines
5.7 KiB
Java
/* MyVerifyDecryptCallback.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
|
|
*/
|
|
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.nio.*;
|
|
import java.util.*;
|
|
import javax.crypto.Mac;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
import javax.crypto.Cipher;
|
|
import java.nio.ByteBuffer;
|
|
import com.wolfssl.*;
|
|
|
|
/*
|
|
* Example Verify/Decrypt callback implementation. For use when
|
|
* HAVE_ENCRYPT_THEN_MAC is defined, which can be tested from Java using
|
|
* WolfSSL.encryptThenMacEnabled().
|
|
*
|
|
* This example callback has been modeled directly after the native wolfSSL
|
|
* example callback (myVerifyDecryptCb()) in wolfssl/test.h.
|
|
*
|
|
* NOTE: if native HAVE_ENCRYPT_THEN_MAC is not defined, the DecryptVerify
|
|
* callback needs to be set and used.
|
|
*/
|
|
class MyVerifyDecryptCallback implements WolfSSLVerifyDecryptCallback
|
|
{
|
|
public int verifyDecryptCallback(WolfSSLSession ssl, ByteBuffer decOut,
|
|
byte[] decIn, long decSz, int macContent, int macVerify,
|
|
long[] padSz, Object ctx) {
|
|
|
|
int hmacType = ssl.getHmacType();
|
|
int digestSz = ssl.getHmacSize();
|
|
byte[] myInner = new byte[WolfSSL.WOLFSSL_TLS_HMAC_INNER_SZ];
|
|
byte[] verify = null;
|
|
byte[] keyBytes = null;
|
|
byte[] ivBytes = null;
|
|
String hmacString;
|
|
String tlsStr = "TLS";
|
|
|
|
Cipher cipher = null;
|
|
MyAtomicDecCtx decCtx = (MyAtomicDecCtx) ctx;
|
|
|
|
/* example supports (d)tls AES */
|
|
if (ssl.getBulkCipher() != WolfSSL.wolfssl_aes) {
|
|
System.out.println("MyVerifyDecryptCallback not using AES");
|
|
return -1;
|
|
}
|
|
|
|
try {
|
|
if (!ssl.getVersion().contains(tlsStr)) {
|
|
System.out.println("MyVerifyDecryptCallback not using (D)TLS");
|
|
return -1;
|
|
}
|
|
|
|
ssl.setTlsHmacInner(myInner, decSz, macContent, macVerify);
|
|
|
|
if (hmacType == WolfSSL.SHA) {
|
|
hmacString = "HmacSHA1";
|
|
} else if (hmacType == WolfSSL.SHA256) {
|
|
hmacString = "HmacSHA256";
|
|
} else if (hmacType == WolfSSL.SHA384) {
|
|
hmacString = "HmacSHA384";
|
|
} else if (hmacType == WolfSSL.SHA512) {
|
|
hmacString = "HmacSHA512";
|
|
} else {
|
|
System.out.println("Unsupported HMAC hash type in " +
|
|
"MyVerifyDecryptCallback: " + hmacType);
|
|
return -1;
|
|
}
|
|
|
|
/* construct HMAC key */
|
|
SecretKeySpec hmacKey = new SecretKeySpec(
|
|
ssl.getMacSecret(macVerify), hmacString);
|
|
|
|
/* get Mac instance, initialize with key, compute */
|
|
Mac mac = Mac.getInstance(hmacString);
|
|
mac.init(hmacKey);
|
|
mac.update(myInner, 0, myInner.length);
|
|
mac.update(decIn, 0, (int)decSz);
|
|
verify = mac.doFinal();
|
|
|
|
/* Get MAC (digestSz bytes) off end of decOut for comparison */
|
|
byte[] verifyMac = new byte[digestSz];
|
|
int tmpPos = decOut.position();
|
|
decOut.position(decOut.limit() - digestSz);
|
|
decOut.get(verifyMac);
|
|
decOut.position(tmpPos);
|
|
|
|
if (verifyMac.length != verify.length) {
|
|
System.out.println("MyVerifyDecryptCallback verifyMac length " +
|
|
"different than calculated MAC length");
|
|
return -1;
|
|
}
|
|
|
|
if (!Arrays.equals(verify, verifyMac)) {
|
|
System.out.println("MyVerifyDecryptCallback MAC " +
|
|
"comparison failed");
|
|
return -1;
|
|
}
|
|
|
|
/* Setup AES for decrypt */
|
|
if(!decCtx.isCipherSetup()) {
|
|
int keyLen = ssl.getKeySize();
|
|
SecretKeySpec key = null;
|
|
cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
|
|
|
|
/* Decrypt is from other side (peer) */
|
|
if (ssl.getSide() == WolfSSL.WOLFSSL_SERVER_END) {
|
|
keyBytes = ssl.getClientWriteKey();
|
|
ivBytes = ssl.getClientWriteIV();
|
|
} else {
|
|
keyBytes = ssl.getServerWriteKey();
|
|
ivBytes = ssl.getServerWriteIV();
|
|
}
|
|
|
|
key = new SecretKeySpec(keyBytes, "AES");
|
|
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivBytes));
|
|
decCtx.setCipher(cipher);
|
|
decCtx.isCipherSetup(true);
|
|
} else {
|
|
cipher = decCtx.getCipher();
|
|
|
|
if (cipher == null) {
|
|
System.out.println("Cipher was not previously set up");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Decrypt */
|
|
decOut.position(0);
|
|
decOut.put(cipher.doFinal(decIn, 0, (int)decSz));
|
|
decOut.flip();
|
|
|
|
byte padVal = decOut.get((int)decSz - 1);
|
|
padSz[0] = (long)padVal + 1;
|
|
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|