79673442

Date: 2025-06-20 13:23:48
Score: 3
Natty:
Report link

So this has worked for me as well! But can anyone help me with the C# decryption logic? Below, I'm sharing the Java decryption code and the equivalent C# code, too. The C# code throws the error "MAC check failed. Data may be tampered.", indicating that calcTag.SequenceEqual(tag) is failing.

I'm also sharing the Java encryption logic here.

The Java Encryption Code:

package encrypt;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;

import javax.crypto.Cipher;

import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.IESParameterSpec;

public class Encrypt {

    public static void main(String[] args) throws Exception {
    
        
            // plain-text request
            String input = "thIS IS MANISH";
            String subid = "SO29";
            String aiId = "SA29";
            String currentTime = String.valueOf(Instant.now().toEpochMilli());
            String expiryTime = String.valueOf(Instant.now().toEpochMilli() +(Integer.parseInt("180000")));
     
            String signature = signPayload(input, currentTime, expiryTime);
            String protectedInfo = Base64.getEncoder().encodeToString(getProtectedDetails(subid,aiId, currentTime, expiryTime).getBytes());
            String encryptedpayload = encryptECIES(input);
            String finalPayload = "{\"payload\":\"" + encryptedpayload + "\",\"signatures\":[{\"signature\":\"" + signature +
                    "\",\"protectedInfo\":\"" + protectedInfo + "\"}]}";
            System.out.println(finalPayload);
     
        }
        private static String getProtectedDetails(String subscriberId, String keyID, String currentTime, String expiryTime) {
            return "keyId=\"" + subscriberId + "|" + keyID + "|" + "ecdsa" + "\",algorithm=\"ecdsa\",created=\"" +
                    currentTime +
                    "\",expires=\"" + expiryTime +
                    "\",headers=\" (created)(expires)digest\"";
        }
        public static String blake2b512(String input){
     
            System.out.println(input);
     
     
            // Create Blake2b digest
            Blake2bDigest blakeHash = new Blake2bDigest(512);
            blakeHash.update(input.getBytes(), 0, input.getBytes().length);
            byte[] hashByte = new byte[blakeHash.getDigestSize()];
            blakeHash.doFinal(hashByte, 0);
            System.out.println("Blake2b-512 Hash: " );
            String encodedString = Base64.getEncoder().encodeToString(hashByte);
            System.out.println(encodedString);
            return encodedString;
        }
     
        public static String signPayload(String input, String currentTime, String expiryTime) throws NoSuchAlgorithmException, SignatureException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {
     
            String concatenated = "(created):" + currentTime + "\n"
                    + "(expires):" + expiryTime + "\n" + "digest:BLAKE2b-512="
                    + blake2b512(input);
            System.out.println(concatenated);
     
            // partner's private key
            //String encodedPrivateKey = "TUlHSEFnRUFNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQkcwd2F3SUJBUVFnRlNsV0UwaS8wWC9iYVE0N1lMUUNST1BSTFFnMXRib1F4L2xQeW4xUUZwT2hSQU5DQUFRVHpqMUsvMmc5blZTU3hTR0o4VnpzWU90Ui9rVFN5WG02dXNGSUJNbHEzcHQ1Nzh6cjlCZkY0aTIzOGRodzhWQ05obi9jQmZwQTJoNGJFK3JoTkJ3NA==";
            String encodedPrivateKey = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFSlWE0i/0X/baQ47YLQCROPRLQg1tboQx/lPyn1QFpOhRANCAAQTzj1K/2g9nVSSxSGJ8VzsYOtR/kTSyXm6usFIBMlq3pt578zr9BfF4i238dhw8VCNhn/cBfpA2h4bE+rhNBw4";

            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(encodedPrivateKey));
            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
            // Original message to be signed
     
     
            // Create a signature instance using SHA-512 with ECDSA
            Signature ecdsaSignature = Signature.getInstance("SHA512withECDSA");
     
            // Initialize the signature instance with the private key for signing
            ecdsaSignature.initSign(privateKey);
            // Supply the data to be signed
            byte[] data = concatenated.getBytes(StandardCharsets.UTF_8);
            ecdsaSignature.update(data);    
     
            // Generate the digital signature
            byte[] digitalSignature = ecdsaSignature.sign();
     
            // Convert the digital signature to Base64 for easy display and transmission
            String base64Signature = Base64.getEncoder().encodeToString(digitalSignature);
            System.out.println("Digital Signature (Base64): " + base64Signature);
     
            return base64Signature;
        }
     
        public static String encryptECIES(String payLoad) throws Exception {
            Security.addProvider(new BouncyCastleProvider());
            //npci's public key
            String key = "-----BEGIN PUBLIC KEY-----\r\n"
                    + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEa2MrinHuivU0kE3hyJxxgoq96/N\r\n"
                    + "DiTw8KxI6A+WXSStWrKUPwLYHdzKw5Z314ry6D9lpkMZflTP0BeCIZRwuw==\r\n"
                    + "-----END PUBLIC KEY-----\r\n"
                    + "";
            String base64PublicKey = key
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s", "");
            
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode((base64PublicKey)));
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("ECIESwithSHA512/NONE/NoPadding");
            IESParameterSpec iesParamSpec = new IESParameterSpec(null, null, 256);
            cipher.init(1, publicKey, iesParamSpec);
            return Base64.getEncoder().encodeToString(cipher.doFinal(payLoad.getBytes()));
     
        }
     

    }


The Java Decryption Code:

 package encrypt;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.IESParameterSpec;
import org.json.JSONObject;

public class Decrypt {

    public static void main(String[] args) throws Exception{
          // encrypted payload
         
          
          String input = "{\"payload\":\"BlZphrMQwR/8s6VKQtciQtZGRWH07Lgk7IJWk1QIywmq7WbV0myS8oH+URn1RJziEJ4nC5ShODAF2iOOTt8gPgsXT23Gkq4orFqiyL2I\",\"protectedInfo\":\"a2V5SWQ9IlNPMjl8U0EyOXxlY2RzYSIsYWxnb3JpdGhtPSJlY2RzYSIsY3JlYXRlZD0iMTc0OTQ2MTkxMzc0MSIsZXhwaXJlcz0iMTc0OTQ2MjIxMzc0MiIsaGVhZGVycz0iIChjcmVhdGVkKShleHBpcmVzKWRpZ2VzdCI=\"}]}";
            JSONObject jsonObject = new JSONObject(input);
     
            String payload = createDecryptionCipher(jsonObject.getString("payload"));
            String protectedInfo = jsonObject.getJSONArray("signatures").getJSONObject(0).getString("protectedInfo");
            String decodedProtectedInfo = new String(Base64.getDecoder().decode(protectedInfo.getBytes()));
            String signature = jsonObject.getJSONArray("signatures").getJSONObject(0).getString("signature");
            System.out.println("decodedProtectedInfo : " + decodedProtectedInfo);
            System.out.println("payload : " + payload);
            System.out.println("signature : " +signature);
     
            //NPCI's public key
            String encodedPublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEE849Sv9oPZ1UksUhifFc7GDrUf5E0sl5urrBSATJat6bee/M6/QXxeItt/HYcPFQjYZ/3AX6QNoeGxPq4TQcOA==";
            PublicKey publicKey = convertToPublicKey(Base64.getDecoder().decode(encodedPublicKey));
     
            boolean result = validateSignature(signature, decodedProtectedInfo, payload, publicKey);
     
            if(result){
                System.out.println("signature validation successfully");
                System.out.println("payload: " + payload);
            }else{
                System.out.println("signature validation failed");
            }
        }
     
        public static PublicKey convertToPublicKey(byte[] encodePubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodePubKey);
            return keyFactory.generatePublic(x509EncodedKeySpec);
        }
     
        private static String createDecryptionCipher(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InterruptedException,
                InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("ECIESwithSHA512/NONE/NoPadding");
     
            // partner's private key
            String privateKey = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg51083sOVh5xvX7cgK/pF3/v6hMhZFGYxMYoJwYNLtFuhRANCAAQRrYyuKce6K9TSQTeHInHGCir3r80OJPDwrEjoD5ZdJK1aspQ/Atgd3MrDlnfXivLoP2WmQxl+VM/QF4IhlHC7";
            IESParameterSpec iesParamSpec = new IESParameterSpec(null, null,256);
            cipher.init(2, getDecryptedPrivateKey(privateKey), iesParamSpec);
            return new String(cipher.doFinal(Base64.getDecoder().decode(input.getBytes())));
        }
     
        private static PrivateKey getDecryptedPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            return keyFactory.generatePrivate(privateKeySpec);
        }
     
        public static boolean validateSignature(String signature, String protectedInfo, String payload, PublicKey key)
                throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
            Map<String, String> timeStamp = getTimeStamps(protectedInfo);
            validateExpiryTime(timeStamp.get("expiryTime"));
            byte[] sign = Base64.getDecoder().decode(signature.getBytes());
            byte[] hashValue = blakeHashing(payload);
            String concatenated = "(created):" + timeStamp.get("createdTime") + "\n"
                    + "(expires):" + timeStamp.get("expiryTime") + "\n" + "digest:BLAKE2b-512="
                    + Base64.getEncoder().encodeToString(hashValue);
     
            return verify(concatenated.getBytes(), sign, key);
        }
        private static boolean verify(byte[] hashValue, byte[] signature, PublicKey publicKey) throws NoSuchAlgorithmException,
                InvalidKeyException, SignatureException {
            Signature verifier = Signature.getInstance("SHA512withECDSA");
            verifier.initVerify(publicKey);
            verifier.update(hashValue);
            return verifier.verify(signature);
        }
     
        public static byte[] blakeHashing(String input){
     
            System.out.println(input);
     
     
            // Create Blake2b digest
            Blake2bDigest blakeHash = new Blake2bDigest(512);
            blakeHash.update(input.getBytes(), 0, input.getBytes().length);
            byte[] hashByte = new byte[blakeHash.getDigestSize()];
            blakeHash.doFinal(hashByte, 0);
            return hashByte;
        }
        private static void validateExpiryTime(String s) throws SignatureException {
            long currentTime = Instant.now().toEpochMilli();
            if (currentTime > Long.parseLong(s)) {
                System.out.println("Signature Expired");
                throw new SignatureException("Signature Expired");
            }
        }
     
        private static Map<String, String> getTimeStamps(String decodedProtectedInfo) throws SignatureException {
            String[] protectedVal = decodedProtectedInfo.split(",");
            String[] currentTimeString = protectedVal[2].split("=");
            String currentTimeStamp = currentTimeString[1].substring(1, currentTimeString[1].length() - 1);
            String[] expireTimeString = protectedVal[3].split("=");
            String expireTimeStamp = expireTimeString[1].substring(1, expireTimeString[1].length() - 1);
            Map<String, String> map = new HashMap<>();
            map.put("createdTime", currentTimeStamp);
            map.put("expiryTime", expireTimeStamp);
            return map;
        }
    }

The java equivalent C# code:

 public static string DecryptECIES(string base64Input, ECPrivateKeyParameters privateKey)
 {
     byte[] inputBytes = Convert.FromBase64String(base64Input);
     int ephLen = 65, tagLen = 64;
     int ctLen = inputBytes.Length - ephLen - tagLen;
     if (ctLen <= 0) throw new Exception("Invalid input.");

     byte[] ephPubBytes = inputBytes.Take(ephLen).ToArray();
     byte[] ciphertext = inputBytes.Skip(ephLen).Take(ctLen).ToArray();
     byte[] tag = inputBytes.Skip(ephLen + ctLen).ToArray();

     byte[] derivation = new byte[0];
     byte[] encoding = new byte[0];
     byte[] L = GetLengthTag(encoding);

     ECDomainParameters ecParams = privateKey.Parameters;
     Org.BouncyCastle.Math.EC.ECPoint q = ecParams.Curve.DecodePoint(ephPubBytes);
     ECPublicKeyParameters ephPubKey = new ECPublicKeyParameters(q, ecParams);

     ECDHBasicAgreement agreement = new ECDHBasicAgreement();
     agreement.Init(privateKey);
     BigInteger sharedSecret = agreement.CalculateAgreement(ephPubKey);
     byte[] agreementBytes = Arrays.Concatenate(ephPubBytes, BigIntegers.AsUnsignedByteArray(agreement.GetFieldSize(), sharedSecret));

     Kdf2BytesGenerator kdf = new Kdf2BytesGenerator(new Sha512Digest());
     kdf.Init(new KdfParameters(agreementBytes, derivation));
     byte[] KEnc = new byte[ciphertext.Length];
     byte[] KMac = new byte[64];
     byte[] K = new byte[KEnc.Length + KMac.Length];
     kdf.GenerateBytes(K, 0, K.Length);
     Array.Copy(K, 0, KMac, 0, KMac.Length);
     Array.Copy(K, KMac.Length, KEnc, 0, KEnc.Length);

     HMac mac = new HMac(new Sha512Digest());
     mac.Init(new KeyParameter(KMac));
     mac.BlockUpdate(ciphertext, 0, ciphertext.Length);
     mac.BlockUpdate(encoding, 0, encoding.Length);
     mac.BlockUpdate(L, 0, L.Length);
     byte[] calcTag = new byte[mac.GetMacSize()];
     mac.DoFinal(calcTag, 0);

     if (!calcTag.SequenceEqual(tag))
         throw new CryptographicException("MAC check failed. Data may be tampered.");

     byte[] plaintext = new byte[ciphertext.Length];
     for (int i = 0; i < ciphertext.Length; i++)
         plaintext[i] = (byte)(ciphertext[i] ^ KEnc[i]);

     return Encoding.UTF8.GetString(plaintext);
 }
Reasons:
  • Blacklisted phrase (1): help me
  • Whitelisted phrase (-1): worked for me
  • RegEx Blacklisted phrase (3): can anyone help me
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Low reputation (1):
Posted by: Achyut