/* MyDecryptVerifyCallback.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 Decrypt Verify callback implementation. * NOTE: if native HAVE_ENCRYPT_THEN_MAC is defined, the VerifyDecrypt * callback needs to be used. */ class MyDecryptVerifyCallback implements WolfSSLDecryptVerifyCallback { public int decryptVerifyCallback(WolfSSLSession ssl, ByteBuffer decOut, byte[] decIn, long decSz, int macContent, int macVerify, long[] padSz, Object ctx) { int ret = 0; int macInSz = 0; int ivExtra = 0; long pad = 0; long padByte = 0; String hmacString; String tlsStr = "TLS"; byte[] keyBytes = null; byte[] ivBytes = null; int digestSz = ssl.getHmacSize(); byte[] myInner = new byte[WolfSSL.WOLFSSL_TLS_HMAC_INNER_SZ]; byte[] verify = new byte[WolfSSL.getHmacMaxSize()]; MyAtomicDecCtx decCtx = (MyAtomicDecCtx) ctx; Cipher cipher = null; /* example supports (d)tls AES */ if (ssl.getBulkCipher() != WolfSSL.wolfssl_aes) { System.out.println("MyDecryptVerifyCallback not using AES"); return -1; } try { if (!ssl.getVersion().contains(tlsStr)) { System.out.println("MyDecryptVerifyCallback not using (D)TLS"); return -1; } /* setup AES */ 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.put(cipher.doFinal(decIn, 0, (int)decSz)); decOut.flip(); if (ssl.getCipherType() == WolfSSL.WOLFSSL_AEAD_TYPE) { padSz[0] = ssl.getAeadMacSize(); return 0; } if (ssl.getCipherType() == WolfSSL.WOLFSSL_BLOCK_TYPE) { pad = decOut.get((int)decSz - 1); padByte = 1; if (ssl.isTLSv1_1() == 1) ivExtra = ssl.getCipherBlockSize(); } padSz[0] = ssl.getHmacSize() + pad + padByte; macInSz = (int) (decSz - ivExtra - digestSz - pad - padByte); ssl.setTlsHmacInner(myInner, macInSz, macContent, macVerify); int hmacType = ssl.getHmacType(); 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 " + "MyDecryptVerifyCallback: " + hmacType); return -1; } /* get Hmac SHA-1 key */ SecretKeySpec signingKey = new SecretKeySpec( ssl.getMacSecret(macVerify), hmacString); /* get Hmac SHA-1 instance and initialize with signing key */ Mac mac = Mac.getInstance(hmacString); mac.init(signingKey); /* get tmp array for encrypted MAC */ byte[] tmpMac = new byte[(int)macInSz]; ByteBuffer tmpBuf = decOut.duplicate(); tmpBuf.position(ivExtra); tmpBuf.limit(ivExtra + tmpMac.length + 1); tmpBuf.slice().get(tmpMac, 0, tmpMac.length); /* compute Hmac on signing data */ mac.update(myInner, 0, myInner.length); mac.update(tmpMac, 0, (int)macInSz); verify = mac.doFinal(); /* do comparison */ int begin = (int) (decSz - digestSz - pad - padByte); byte[] subArray = new byte[digestSz]; ByteBuffer tmpDigest = decOut.duplicate(); tmpDigest.position(begin); tmpDigest.limit(begin + digestSz + 1); tmpDigest.slice().get(subArray); if (!Arrays.equals(verify, subArray)) { System.out.println("MyDecryptVerifyCallback verify failed"); return -1; } } catch (Exception e) { e.printStackTrace(); } return ret; } }