public static IBufferedCipher GetCipher(
string algorithm)
{
if (algorithm == null)
throw new ArgumentNullException("algorithm");
algorithm = algorithm.ToUpper(CultureInfo.InvariantCulture);
string aliased = (string) algorithms[algorithm];
if (aliased != null)
algorithm = aliased;
IBasicAgreement iesAgreement = null;
if (algorithm == "IES")
{
iesAgreement = new DHBasicAgreement();
}
else if (algorithm == "ECIES")
{
iesAgreement = new ECDHBasicAgreement();
}
if (iesAgreement != null)
{
return new BufferedIesCipher(
new IesEngine(
iesAgreement,
new Kdf2BytesGenerator(
new Sha1Digest()),
new HMac(
new Sha1Digest())));
}
if (algorithm.StartsWith("PBE"))
{
if (algorithm.EndsWith("-CBC"))
{
if (algorithm == "PBEWITHSHA1ANDDES-CBC")
{
return new PaddedBufferedBlockCipher(
new CbcBlockCipher(new DesEngine()));
}
else if (algorithm == "PBEWITHSHA1ANDRC2-CBC")
{
return new PaddedBufferedBlockCipher(
new CbcBlockCipher(new RC2Engine()));
}
else if (Strings.IsOneOf(algorithm,
"PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"))
{
return new PaddedBufferedBlockCipher(
new CbcBlockCipher(new DesEdeEngine()));
}
else if (Strings.IsOneOf(algorithm,
"PBEWITHSHAAND128BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC"))
{
return new PaddedBufferedBlockCipher(
new CbcBlockCipher(new RC2Engine()));
}
}
else if (algorithm.EndsWith("-BC") || algorithm.EndsWith("-OPENSSL"))
{
if (Strings.IsOneOf(algorithm,
"PBEWITHSHAAND128BITAES-CBC-BC",
"PBEWITHSHAAND192BITAES-CBC-BC",
"PBEWITHSHAAND256BITAES-CBC-BC",
"PBEWITHSHA256AND128BITAES-CBC-BC",
"PBEWITHSHA256AND192BITAES-CBC-BC",
"PBEWITHSHA256AND256BITAES-CBC-BC",
"PBEWITHMD5AND128BITAES-CBC-OPENSSL",
"PBEWITHMD5AND192BITAES-CBC-OPENSSL",
"PBEWITHMD5AND256BITAES-CBC-OPENSSL"))
{
return new PaddedBufferedBlockCipher(
new CbcBlockCipher(new AesFastEngine()));
}
}
}
string[] parts = algorithm.Split('/');
IBlockCipher blockCipher = null;
IAsymmetricBlockCipher asymBlockCipher = null;
IStreamCipher streamCipher = null;
string algorithmName = parts[0];
CipherAlgorithm cipherAlgorithm;
try
{
cipherAlgorithm = (CipherAlgorithm)Enums.GetEnumValue(typeof(CipherAlgorithm), algorithmName);
}
catch (ArgumentException)
{
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
switch (cipherAlgorithm)
{
case CipherAlgorithm.AES:
blockCipher = new AesFastEngine();
break;
case CipherAlgorithm.ARC4:
streamCipher = new RC4Engine();
break;
case CipherAlgorithm.BLOWFISH:
blockCipher = new BlowfishEngine();
break;
case CipherAlgorithm.CAMELLIA:
blockCipher = new CamelliaEngine();
break;
case CipherAlgorithm.CAST5:
blockCipher = new Cast5Engine();
break;
case CipherAlgorithm.CAST6:
blockCipher = new Cast6Engine();
break;
case CipherAlgorithm.DES:
blockCipher = new DesEngine();
break;
case CipherAlgorithm.DESEDE:
blockCipher = new DesEdeEngine();
break;
case CipherAlgorithm.ELGAMAL:
asymBlockCipher = new ElGamalEngine();
break;
case CipherAlgorithm.GOST28147:
blockCipher = new Gost28147Engine();
break;
case CipherAlgorithm.HC128:
streamCipher = new HC128Engine();
break;
case CipherAlgorithm.HC256:
streamCipher = new HC256Engine();
break;
#if INCLUDE_IDEA
case CipherAlgorithm.IDEA:
blockCipher = new IdeaEngine();
break;
#endif
case CipherAlgorithm.NOEKEON:
blockCipher = new NoekeonEngine();
break;
case CipherAlgorithm.PBEWITHSHAAND128BITRC4:
case CipherAlgorithm.PBEWITHSHAAND40BITRC4:
streamCipher = new RC4Engine();
break;
case CipherAlgorithm.RC2:
blockCipher = new RC2Engine();
break;
case CipherAlgorithm.RC5:
blockCipher = new RC532Engine();
break;
case CipherAlgorithm.RC5_64:
blockCipher = new RC564Engine();
break;
case CipherAlgorithm.RC6:
blockCipher = new RC6Engine();
break;
case CipherAlgorithm.RIJNDAEL:
blockCipher = new RijndaelEngine();
break;
case CipherAlgorithm.RSA:
asymBlockCipher = new RsaBlindedEngine();
break;
case CipherAlgorithm.SALSA20:
streamCipher = new Salsa20Engine();
break;
case CipherAlgorithm.SEED:
blockCipher = new SeedEngine();
break;
case CipherAlgorithm.SERPENT:
blockCipher = new SerpentEngine();
break;
case CipherAlgorithm.SKIPJACK:
blockCipher = new SkipjackEngine();
break;
case CipherAlgorithm.TEA:
blockCipher = new TeaEngine();
break;
case CipherAlgorithm.TWOFISH:
blockCipher = new TwofishEngine();
break;
case CipherAlgorithm.VMPC:
streamCipher = new VmpcEngine();
break;
case CipherAlgorithm.VMPC_KSA3:
streamCipher = new VmpcKsa3Engine();
break;
case CipherAlgorithm.XTEA:
blockCipher = new XteaEngine();
break;
default:
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
if (streamCipher != null)
{
if (parts.Length > 1)
throw new ArgumentException("Modes and paddings not used for stream ciphers");
return new BufferedStreamCipher(streamCipher);
}
bool cts = false;
bool padded = true;
IBlockCipherPadding padding = null;
IAeadBlockCipher aeadBlockCipher = null;
if (parts.Length > 2)
{
if (streamCipher != null)
throw new ArgumentException("Paddings not used for stream ciphers");
string paddingName = parts[2];
CipherPadding cipherPadding;
if (paddingName == "")
{
cipherPadding = CipherPadding.RAW;
}
else if (paddingName == "X9.23PADDING")
{
cipherPadding = CipherPadding.X923PADDING;
}
else
{
try
{
cipherPadding = (CipherPadding)Enums.GetEnumValue(typeof(CipherPadding), paddingName);
}
catch (ArgumentException)
{
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
}
switch (cipherPadding)
{
case CipherPadding.NOPADDING:
padded = false;
break;
case CipherPadding.RAW:
break;
case CipherPadding.ISO10126PADDING:
case CipherPadding.ISO10126D2PADDING:
case CipherPadding.ISO10126_2PADDING:
padding = new ISO10126d2Padding();
break;
case CipherPadding.ISO7816_4PADDING:
case CipherPadding.ISO9797_1PADDING:
padding = new ISO7816d4Padding();
break;
case CipherPadding.ISO9796_1:
case CipherPadding.ISO9796_1PADDING:
asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher);
break;
case CipherPadding.OAEP:
case CipherPadding.OAEPPADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher);
break;
case CipherPadding.OAEPWITHMD5ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest());
break;
case CipherPadding.OAEPWITHSHA1ANDMGF1PADDING:
case CipherPadding.OAEPWITHSHA_1ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest());
break;
case CipherPadding.OAEPWITHSHA224ANDMGF1PADDING:
case CipherPadding.OAEPWITHSHA_224ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest());
break;
case CipherPadding.OAEPWITHSHA256ANDMGF1PADDING:
case CipherPadding.OAEPWITHSHA_256ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest());
break;
case CipherPadding.OAEPWITHSHA384ANDMGF1PADDING:
case CipherPadding.OAEPWITHSHA_384ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest());
break;
case CipherPadding.OAEPWITHSHA512ANDMGF1PADDING:
case CipherPadding.OAEPWITHSHA_512ANDMGF1PADDING:
asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest());
break;
case CipherPadding.PKCS1:
case CipherPadding.PKCS1PADDING:
asymBlockCipher = new Pkcs1Encoding(asymBlockCipher);
break;
case CipherPadding.PKCS5:
case CipherPadding.PKCS5PADDING:
case CipherPadding.PKCS7:
case CipherPadding.PKCS7PADDING:
padding = new Pkcs7Padding();
break;
case CipherPadding.TBCPADDING:
padding = new TbcPadding();
break;
case CipherPadding.WITHCTS:
cts = true;
break;
case CipherPadding.X923PADDING:
padding = new X923Padding();
break;
case CipherPadding.ZEROBYTEPADDING:
padding = new ZeroBytePadding();
break;
default:
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
}
string mode = "";
if (parts.Length > 1)
{
mode = parts[1];
int di = GetDigitIndex(mode);
string modeName = di >= 0 ? mode.Substring(0, di) : mode;
try
{
CipherMode cipherMode = modeName == ""
? CipherMode.NONE
: (CipherMode)Enums.GetEnumValue(typeof(CipherMode), modeName);
switch (cipherMode)
{
case CipherMode.ECB:
case CipherMode.NONE:
break;
case CipherMode.CBC:
blockCipher = new CbcBlockCipher(blockCipher);
break;
case CipherMode.CCM:
aeadBlockCipher = new CcmBlockCipher(blockCipher);
break;
case CipherMode.CFB:
{
int bits = (di < 0)
? 8 * blockCipher.GetBlockSize()
: int.Parse(mode.Substring(di));
blockCipher = new CfbBlockCipher(blockCipher, bits);
break;
}
case CipherMode.CFBDCP:
{
int bits = (di < 0)
? 8 * blockCipher.GetBlockSize()
: int.Parse(mode.Substring(di));
blockCipher = new CfbDCPCipher(blockCipher, bits);
break;
}
case CipherMode.CTR:
blockCipher = new SicBlockCipher(blockCipher);
break;
case CipherMode.CTS:
cts = true;
blockCipher = new CbcBlockCipher(blockCipher);
break;
case CipherMode.EAX:
aeadBlockCipher = new EaxBlockCipher(blockCipher);
break;
case CipherMode.GCM:
aeadBlockCipher = new GcmBlockCipher(blockCipher);
break;
case CipherMode.GOFB:
blockCipher = new GOfbBlockCipher(blockCipher);
break;
case CipherMode.OFB:
{
int bits = (di < 0)
? 8 * blockCipher.GetBlockSize()
: int.Parse(mode.Substring(di));
blockCipher = new OfbBlockCipher(blockCipher, bits);
break;
}
case CipherMode.OPENPGPCFB:
blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
break;
case CipherMode.SIC:
if (blockCipher.GetBlockSize() < 16)
{
throw new ArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
}
blockCipher = new SicBlockCipher(blockCipher);
break;
default:
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
}
catch (ArgumentException)
{
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}
}
if (aeadBlockCipher != null)
{
if (cts)
throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers.");
if (padded && parts.Length > 2 && parts[2] != "")
throw new SecurityUtilityException("Bad padding specified for AEAD cipher.");
return new BufferedAeadBlockCipher(aeadBlockCipher);
}
if (blockCipher != null)
{
if (cts)
{
return new CtsBlockCipher(blockCipher);
}
if (padding != null)
{
return new PaddedBufferedBlockCipher(blockCipher, padding);
}
if (!padded || blockCipher.IsPartialBlockOkay)
{
return new BufferedBlockCipher(blockCipher);
}
return new PaddedBufferedBlockCipher(blockCipher);
}
if (asymBlockCipher != null)
{
return new BufferedAsymmetricBlockCipher(asymBlockCipher);
}
throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
}