Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyPair encryption and decryption generated garbage characters at the beginning #1632

Closed
marshmello275 opened this issue Apr 20, 2024 · 1 comment

Comments

@marshmello275
Copy link

marshmello275 commented Apr 20, 2024

`public class KeyPairCryptoHandler {

private static final String KEY_ALGORITHM = "EC";
private static final String CIPHER_ALGORITHM = "ECIESwithAES-CBC";
private static final String STD_NAME = "secp256r1";
private static final IESParameterSpec IES_PARAM_SPEC;

static {
    SecureRandom random = new SecureRandom();
    byte[] nonce = new byte[16];
    random.nextBytes(nonce);
    IES_PARAM_SPEC = new IESParameterSpec(null, null, 256, 256, nonce, false);
}

private PublicKey pubKey;
private Cipher iesCipher;
private Cipher iesDecipher;

public KeyPairCryptoHandler() throws Exception {
    // set provider
    Security.addProvider(new BouncyCastleProvider());
    // generate key pair
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEY_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    keyGen.initialize(new ECGenParameterSpec(STD_NAME));
    KeyPair keyPair = keyGen.generateKeyPair();
    this.pubKey = keyPair.getPublic();
    // initialize Cipher
    iesCipher = Cipher.getInstance(CIPHER_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    iesCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), IES_PARAM_SPEC);
    // initialize deCipher
    iesDecipher = Cipher.getInstance(CIPHER_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    iesDecipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate(), iesCipher.getParameters());
}

/**
 * encrypt using the instance's public key
 */
public String encrypt(String input) throws Exception {
    byte[] ciphertext = iesCipher.doFinal(input.getBytes());
    return Base64.getEncoder().encodeToString(ciphertext);
}

/**
 * decrypt using the instance's private key
 */
public String decrypt(String encrptedStr) throws Exception {
    byte[] encryptedByte = Base64.getDecoder().decode(encrptedStr);
    byte[] decryptedByte = iesDecipher.doFinal(encryptedByte);
    return new String(decryptedByte);
}

/**
 * convert PublicKey into encoded string
 */
public String getEncodedPubKey() {
    return Base64.getEncoder().encodeToString(this.pubKey.getEncoded());
}

/**
 * convert encoded public key string into PublicKey
 * @param encodedPubKey encoded PublicKey string
 */
public static PublicKey getPubKey(String encodedPubKey) throws Exception {
    byte[] decodedKey = Base64.getDecoder().decode(encodedPubKey);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    return keyFactory.generatePublic(keySpec);
}

/**
 * encrypt the input using provided PublicKey encoder String
 * @param encodedPublicKey encoded public key String
 * @param input
 */
public static String encrypt(String input, String encodedPubKey) throws Exception {
    Cipher iesCipher = Cipher.getInstance(CIPHER_ALGORITHM);
    iesCipher.init(Cipher.ENCRYPT_MODE, getPubKey(encodedPubKey), IES_PARAM_SPEC);
    byte[] ciphertext = iesCipher.doFinal(input.getBytes());
    return Base64.getEncoder().encodeToString(ciphertext);
}

}`

Im having two servers and communicating between those two servers. While sending a request to server, i ll send public key in the request itself. Will encrypt the Response using that public key and send it to the client server. The client will decrypt the response with the private key it has. But im getting garbage characters at the begging. Please help with this.

Sample code using above class:

ServerA:

KeyPairCryptoHandler kpch = new KeyPairCryptoHandler();
  Stirng encodedPubKey = kpch.getEncodedPubKey();
  //will send this encoded pubkey in request param.
  //go to serverB code and come back
  String encryptedResponse = get the response;
  String decryptedResponse = kpch.decrypt(encryptedResponse);

ServerB

String pubKey = req.getParam(PubKey);
 String encryptedResponse = KeyPayrCryptoHandler.encrypt(responseToBeSent, pubKey);
 return encryptedResponse;
 //go back to serverA code.

Actual decrypted string:

}O�!�+�/��A�� the text to be decrypted

Expected decrypted string:

good morning ! the text to be decrypted

how to resolve this?

@tonywasher
Copy link
Contributor

The fact that the first 16 bytes are incorrect, but the remainder of the message is correctly decrypted using a CBC cipher shows that your are using an incorrect nonce for decryption.

The nonce is created as a random set of 16 bytes in each instance of your program meaning that each server will create a different random nonce. You mention that you send the public key in the request, but make no mention of also sending the nonce value.

You need to also send the nonce in the request since there is no other way for the receiving server to determine the correct nonce to use for decryption

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants