• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Avec112 / commons-security / 18657491219

20 Oct 2025 03:49PM UTC coverage: 89.496% (+2.8%) from 86.722%
18657491219

push

github

Avec112
Rename builder `optional()` methods to `withMode()` and `withStrength()` and update references

- Refactored `EncryptBuilder` and `DecryptBuilder` to use `withMode()` and `withStrength()` methods for clarity and consistency.
- Updated `HybridCryptoTest` to reflect the method renaming.

27 of 40 branches covered (67.5%)

Branch coverage included in aggregate %.

399 of 436 relevant lines covered (91.51%)

3.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.95
src/main/java/io/github/avec112/security/crypto/rsa/RsaCipher.java
1
package io.github.avec112.security.crypto.rsa;
2

3
import io.github.avec112.security.crypto.BouncyCastleProviderInitializer;
4
import io.github.avec112.security.crypto.domain.CipherText;
5
import io.github.avec112.security.crypto.domain.PlainText;
6
import io.github.avec112.security.crypto.error.*;
7
import io.github.avec112.security.crypto.random.RandomUtils;
8
import io.github.avec112.security.crypto.validate.Validate;
9
import io.github.avec112.security.encoding.EncodingUtils;
10
import org.apache.commons.lang3.StringUtils;
11
import org.apache.commons.lang3.exception.ExceptionUtils;
12

13
import javax.crypto.BadPaddingException;
14
import javax.crypto.Cipher;
15
import javax.crypto.IllegalBlockSizeException;
16
import javax.crypto.NoSuchPaddingException;
17
import java.nio.charset.StandardCharsets;
18
import java.security.*;
19

20
/**
21
 * RsaCipher is a class that provides methods for encrypting and decrypting texts using the RSA encryption algorithm.
22
 * It extends the BouncyCastleProviderInitializer class, which initializes the BouncyCastle security provider if it is
23
 * not already initialized.
24
 * RSA = Rivest-Shamir-Adleman
25
 * RSA encryption is a type of asymmetric encryption, which uses two different but linked keys. In RSA cryptography,
26
 * both the public and the private keys can encrypt a message. The opposite key from the one used to encrypt a message
27
 * is used to decrypt it.
28
 */
29
public class RsaCipher extends BouncyCastleProviderInitializer {
3✔
30

31
    private static final String RSA_TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
32

33
    /**
34
     * Encrypts the provided plain text using the given public key.
35
     *
36
     * @param plainText  the plain text to be encrypted
37
     * @param publicKey  the public key used for encryption
38
     * @return the encrypted cipher text
39
     * @throws BadCipherConfigurationException if the RSA cipher cannot be initialized properly
40
     */
41
    public CipherText encrypt(PlainText plainText, PublicKey publicKey)
42
            throws BadCipherConfigurationException {
43

44
        Validate.nonNull(plainText, MissingPlainTextException::new);
3✔
45
        Validate.nonBlank(plainText.getValue(), BlankPlainTextException::new);
4✔
46
        Validate.nonNull(publicKey, MissingPublicKeyException::new);
3✔
47

48
        try {
49
            byte[] input = plainText.getValue().getBytes(StandardCharsets.UTF_8);
5✔
50
            byte[] cipherText = processCipher(Cipher.ENCRYPT_MODE, publicKey, input);
6✔
51
            return new CipherText(EncodingUtils.base64Encode(cipherText));
6✔
52
        } catch (Exception e) {
×
53
            throw new BadCipherConfigurationException(ExceptionUtils.getRootCauseMessage(e), e);
×
54
        }
55
    }
56

57
    /**
58
     * Decrypts the given cipher text using the provided private key.
59
     *
60
     * @param cipherText  the cipher text to be decrypted
61
     * @param privateKey  the private key to be used for decryption
62
     * @return the decrypted plain text
63
     * @throws BadCipherConfigurationException if the cipher cannot be configured properly
64
     * @throws BadCipherTextException if the cipher text is corrupted or invalid
65
     */
66
    public PlainText decrypt(CipherText cipherText, PrivateKey privateKey)
67
            throws BadCipherConfigurationException, BadCipherTextException {
68

69
        Validate.nonNull(cipherText, MissingCipherTextException::new);
3✔
70
        Validate.nonBlank(cipherText.getValue(), BlankCipherTextException::new);
4✔
71
        Validate.nonNull(privateKey, MissingPrivateKeyException::new);
3✔
72

73
        try {
74
            byte[] decoded = EncodingUtils.base64Decode(cipherText.getValue());
4✔
75
            byte[] decrypted = processCipher(Cipher.DECRYPT_MODE, privateKey, decoded);
6✔
76

77
            String plain = new String(decrypted, StandardCharsets.UTF_8);
6✔
78
            validateDecryptedOutput(plain);
3✔
79

80
            return new PlainText(plain);
5✔
81

82
        } catch (BadPaddingException | IllegalBlockSizeException e) {
1✔
83
            // Typical symptom of corrupt ciphertext or wrong key
84
            throw new BadCipherTextException("Decryption failed due to corrupt cipher text or wrong key");
5✔
85
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
×
86
            throw new BadCipherConfigurationException("RSA cipher configuration failed", e);
×
87
        }
88
    }
89

90
    /**
91
     * Simple sanity check to detect corrupted or meaningless decrypted data.
92
     *
93
     * @param plain the decrypted text as UTF-8
94
     * @throws BadCipherTextException if the output is empty, unreadable, or otherwise invalid
95
     */
96
    private void validateDecryptedOutput(String plain) throws BadCipherTextException {
97
        if (StringUtils.isBlank(plain) || plain.length() < 2 ||
9!
98
                !plain.matches("[\\p{Print}\\p{Space}]+")) {
2!
99
            throw new BadCipherTextException("Decrypted data appears invalid or produced using wrong key");
×
100
        }
101
    }
1✔
102

103
    /**
104
     * Gets the cipher text by performing encryption or decryption using the specified cipher mode and key.
105
     *
106
     * @param cipherMode the cipher mode to use: Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE
107
     * @param key the key used for encryption or decryption
108
     * @param input the input byte array to process
109
     * @return the output cipher text byte array
110
     * @throws NoSuchPaddingException if the cipher padding scheme is invalid
111
     * @throws NoSuchAlgorithmException if the RSA algorithm is not available
112
     * @throws InvalidKeyException if the key is invalid
113
     * @throws IllegalBlockSizeException if the data block is invalid
114
     * @throws BadPaddingException if padding is incorrect (often indicates wrong key)
115
     */
116
    private byte[] processCipher(int cipherMode, Key key, byte[] input)
117
            throws NoSuchPaddingException, NoSuchAlgorithmException,
118
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
119

120
        Validate.nonNull(key, MissingKeyException::new);
3✔
121
        Cipher cipher = initiateCipher(cipherMode, key);
5✔
122
        return cipher.doFinal(input);
4✔
123
    }
124

125
    /**
126
     * Initializes a Cipher object with the specified encryption mode and key.
127
     *
128
     * @param encryptMode the encryption mode to use, either Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE
129
     * @param key the key used for encryption or decryption
130
     * @return the initialized Cipher object
131
     * @throws NoSuchPaddingException if padding configuration is invalid
132
     * @throws NoSuchAlgorithmException if RSA algorithm is unavailable
133
     * @throws InvalidKeyException if key is invalid or unsupported
134
     */
135
    private Cipher initiateCipher(int encryptMode, Key key)
136
            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
137

138
        Validate.nonNull(key, NullPointerException::new);
3✔
139
        Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
3✔
140
        cipher.init(encryptMode, key, RandomUtils.secureRandom());
5✔
141
        return cipher;
2✔
142
    }
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc