# Asymmetric Ciphers

All asymmetric cipher instances are created via `cipherBuilder()` (static import from `Bruce`). Input and output use the [`Bytes`](https://bruce.mirkocaserta.com/api/bytes) universal type.

## Encryptor

Returns an `AsymmetricEncryptor` that encrypts messages with an asymmetric public key.

### Usage examples

```java
KeyStore bobKeystore = keystore("classpath:/keystore-bob.p12", "password".toCharArray(), "PKCS12");
PublicKey bobPublicKey = publicKey(bobKeystore, "bob");

AsymmetricEncryptor encryptor = cipherBuilder()
    .key(bobPublicKey)
    .algorithm("RSA/ECB/PKCS1Padding")
    .buildAsymmetricEncryptor();

// raw bytes → Bytes
Bytes encrypted = encryptor.encrypt(Bytes.from("Hello Bob".getBytes(UTF_8)));

// UTF-8 text → BASE64 string
String enc64 = encryptor.encrypt(Bytes.from("Hello Bob")).encode(BASE64);

// UTF-8 text → HEX string
String encHex = encryptor.encrypt(Bytes.from("Hello Bob")).encode(HEX);
```

### Builder options

```java
import static com.mirkocaserta.bruce.Bruce.Provider.*;
import static com.mirkocaserta.bruce.Bruce.CipherAlgorithm.*;

// String-based algorithm (open-ended, supports any JCA algorithm)
AsymmetricEncryptor encryptor = cipherBuilder()
    .key(publicKey)
    .algorithm(RSA_ECB_PKCS1PADDING)
    .provider(BOUNCY_CASTLE)  // optional, defaults to JCA
    // .provider("BC")        // string-based alternative
    .buildAsymmetricEncryptor();

// Enum-based algorithm (type-safe, IDE auto-completion)
AsymmetricEncryptor encryptor2 = cipherBuilder()
    .key(publicKey)
    .algorithm(AsymmetricAlgorithm.RSA_ECB_PKCS1)
    .provider(BOUNCY_CASTLE)  // optional
    .buildAsymmetricEncryptor();
```

Available `AsymmetricAlgorithm` constants: `RSA`, `RSA_ECB_PKCS1`, `RSA_ECB_OAEP_SHA1_MGF1`, `RSA_ECB_OAEP_SHA256_MGF1`, `RSA_ECB_OAEP_SHA384_MGF1`, `RSA_ECB_OAEP_SHA512_MGF1`, `RSA_ECB_NO_PADDING`.

***

## Decryptor

Returns an `AsymmetricDecryptor` that decrypts messages with an asymmetric private key.

### Usage examples

```java
KeyStore bobKeystore = keystore("classpath:/keystore-bob.p12", "password".toCharArray(), "PKCS12");
PrivateKey bobPrivateKey = privateKey(bobKeystore, "bob", "password".toCharArray());

AsymmetricDecryptor decryptor = cipherBuilder()
    .key(bobPrivateKey)
    .algorithm("RSA/ECB/PKCS1Padding")
    .buildAsymmetricDecryptor();

// Bytes → Bytes
Bytes plain = decryptor.decrypt(encrypted);
String text = plain.asString();

// BASE64 string → String
String plain2 = decryptor.decrypt(Bytes.from(enc64, BASE64)).asString();

// HEX string → String
String plain3 = decryptor.decrypt(Bytes.from(encHex, HEX)).asString();
```

***

## Full Alice ↔ Bob round-trip

```java
KeyStore aliceKs = keystore("classpath:/keystore-alice.p12", "password".toCharArray(), "PKCS12");
KeyStore bobKs   = keystore("classpath:/keystore-bob.p12",   "password".toCharArray(), "PKCS12");

AsymmetricEncryptor encryptForBob   = cipherBuilder().key(publicKey(bobKs, "bob")).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricEncryptor();
AsymmetricDecryptor decryptAsBob    = cipherBuilder().key(privateKey(bobKs, "bob", "password".toCharArray())).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricDecryptor();
AsymmetricEncryptor encryptForAlice = cipherBuilder().key(publicKey(aliceKs, "alice")).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricEncryptor();
AsymmetricDecryptor decryptAsAlice  = cipherBuilder().key(privateKey(aliceKs, "alice", "password".toCharArray())).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricDecryptor();

// Alice → Bob (raw bytes)
Bytes aliceMsg  = Bytes.from("Hello Bob");
Bytes encrypted = encryptForBob.encrypt(aliceMsg);
Bytes decrypted = decryptAsBob.decrypt(encrypted);
assertEquals(aliceMsg, decrypted);

// Bob → Alice (via BASE64 strings)
String bobMsg  = "Hey Alice!";
String enc64   = encryptForAlice.encrypt(Bytes.from(bobMsg)).encode(BASE64);
String dec64   = decryptAsAlice.decrypt(Bytes.from(enc64, BASE64)).asString();
assertEquals(bobMsg, dec64);
```

***

## Encryptor / Decryptor by Key

For runtime key selection:

```java
Map<String, Key> pubKeys  = Map.of("alice", alicePub, "bob", bobPub);
Map<String, Key> privKeys = Map.of("alice", alicePriv, "bob", bobPriv);

AsymmetricEncryptorByKey encryptors = cipherBuilder().keys(pubKeys).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricEncryptorByKey();
AsymmetricDecryptorByKey decryptors = cipherBuilder().keys(privKeys).algorithm("RSA/ECB/PKCS1Padding").buildAsymmetricDecryptorByKey();

Bytes enc = encryptors.encrypt("bob", Bytes.from("Hello Bob"));
Bytes dec = decryptors.decrypt("bob", enc);
```

### Interfaces

```java
@FunctionalInterface
public interface AsymmetricEncryptor {
    Bytes encrypt(Bytes plaintext);
}

@FunctionalInterface
public interface AsymmetricDecryptor {
    Bytes decrypt(Bytes ciphertext);
}

@FunctionalInterface
public interface AsymmetricEncryptorByKey {
    Bytes encrypt(String keyId, Bytes plaintext);
}

@FunctionalInterface
public interface AsymmetricDecryptorByKey {
    Bytes decrypt(String keyId, Bytes ciphertext);
}
```
