Find similar to X509EncodedKeySpec in C# - java

All I need is just to get this lines of code in C#, Actually I can't find X509EncodedKeySpec in C#:
byte[] keyByte = Base64.decode(publicKey);
// generate public key
X509EncodedKeySpec s = new X509EncodedKeySpec(keyByte);
KeyFactory factory = null;
try
{
factory = KeyFactory.getInstance("RSA");
}
catch (NoSuchAlgorithmException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Key pubKey = null;
try
{
pubKey = factory.generatePublic(s);
}
catch (InvalidKeySpecException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

As of .NET Core 3.0 ImportSubjectPublicKeyInfo is available
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importsubjectpublickeyinfo?view=netcore-3.0
You should be able to use it as follows:
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(publicKey, out _);
//do your stuff
}

X509EncodedKeySpec is Java's version of X.509 SubjectPublicKeyInfo. .NET doesn't have any API built-in for reading SubjectPublicKeyInfo. For best results, you want to have a full certificate, then use cert.GetRSAPublicKey().
If you can get the transmitted as the RSA Modulus and RSA (Public) Exponent values then you could build the RSAParameters object to load into a key.
using (RSA rsa = RSA.Create())
{
rsa.ImportParameters(new RSAParameters { Modulus = modulus, Exponent = exponent });
// do public key things
}

Related

What is the algorithm string for 'AGCM256-KW' in java cryptography, to be used in Cipher.getInstance(String algo)?

referring this, I have to encrypt using algorithm AGCM256-­KW. I am using Java Cryptography and I didn't find any such algorithm. Closest I found was AES_256/GCM/NoPadding but it has no KW (Key wrapping).
here is my test code
public void testEncryption(String algo) {
String shared_secret = "LyQnklSrxsk3Ch2+AHi9HoDW#//x1LwM123QP/ln";
try {
// Step 1 - Create SHA-256 digest of the shared key
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(shared_secret.getBytes("UTF-8"));
// Step 2 - generate a 256 bit Content Encryption Key(CEK)
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
SecretKey cek = kg.generateKey();
// Step 3 - encrypt the CEK using 256 bit digest generated in Step 1
// and 96 bit random IV. Algorithm should be
// random 96 bit Initialize Vector
SecureRandom random = new SecureRandom();
// byte iv[] = new byte[96];
// random.nextBytes(iv);
byte iv[] = random.generateSeed(96);
System.out.println("IV: " + toBase64(iv) + " length: " + iv.length);
IvParameterSpec ivspec = new IvParameterSpec(iv);
GCMParameterSpec gspec = new GCMParameterSpec(96, iv);
// encrypt
Cipher cipher = Cipher.getInstance(algo);
System.out.println(String.format("CEK Cipher alg:%S provider:%S", cipher.getAlgorithm(),
cipher.getProvider().getName()));
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(digest, "AES"), gspec);
byte[] result = cipher.doFinal(cek.getEncoded());
System.out.println(String.format("Encrypted CEK :%S", toBase64(result)));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Update 1
I think I can use jose4j library which has APIs for JWE.
Yes, the Visa Token Services appear to be using JWE (now RFC 7516) so you can use jose4j for this. Here's some sample code that shows encrypting and decrypting some content with JWE using A256GCMKW and AGCM256:
// shared secret hashed to key from your example
String shared_secret = "LyQnklSrxsk3Ch2+AHi9HoDW#//x1LwM123QP/ln";
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(shared_secret.getBytes("UTF-8"));
JsonWebEncryption jwe = new JsonWebEncryption();
// A256GCMKW for key wrap
jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.A256GCMKW);
// A256GCM for content encryption
jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM);
// the key (from above)
jwe.setKey(new SecretKeySpec(digest, "AES"));
// whatever content you want to encrypt
jwe.setPayload("some important content to be encrypted and integrity protected");
// Produce the JWE compact serialization, which is where the actual encryption is done.
// The JWE compact serialization consists of five base64url encoded parts
// combined with a dot ('.') character in the general format of
// <header>.<encrypted key>.<initialization vector>.<ciphertext>.<authentication tag>
String serializedJwe = jwe.getCompactSerialization();
// Do something with the JWE. Like send it to some other party over the clouds
// and through the interwebs.
System.out.println("JWE compact serialization: " + serializedJwe);
// That other party, the receiver, can then use JsonWebEncryption to decrypt the message.
JsonWebEncryption receiverJwe = new JsonWebEncryption();
// Set the compact serialization on new Json Web Encryption object
receiverJwe.setCompactSerialization(serializedJwe);
// Symmetric encryption, like we are doing here, requires that both parties have the same key.
// The key will have had to have been securely exchanged out-of-band somehow.
receiverJwe.setKey(new SecretKeySpec(digest, "AES"));
// Get the message that was encrypted in the JWE. This step performs the actual decryption steps.
String plaintext = receiverJwe.getPlaintextString();
// And do whatever you need to do with the clear text message.
System.out.println("plaintext: " + plaintext);
Let's assume you do indeed require AES in GCM mode (I've never heard of AGCM, but I guess this is a logical assumption that it means AES/GCM). Then the following could be used for (un)wrapping a secret key. Note that I didn't get this to work using IvParameterSpec, at least not for the Oracle JCE.
SecretKey sk = new SecretKeySpec(new byte[16], "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, new byte[12]);
cipher.init(Cipher.WRAP_MODE, sk, gcmSpec);
byte[] wrappedKey = cipher.wrap(sk);
System.out.println(Hex.toHexString(wrappedKey));
cipher.init(Cipher.UNWRAP_MODE, sk, gcmSpec);
SecretKey unwrap = (SecretKey) cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
System.out.println(Hex.toHexString(unwrap.getEncoded()));
Note that using SIV mode should probably be somewhat preferred for wrapping keys as you do do not require to store an IV and authentication tag together with the wrapped key (storing the IV is not shown in the example). The above code relies on a unique IV for security (also not shown).
Obviously it's also not a good idea to wrap a key with itself. Sorry, I got a bit lazy here; I've just shown how to use the cipher.
The "KW" refers to "key wrapping," as defined in RFC 3394. The name for this algorithm in the JCE is "AESWrap". So, the transformation should be "AESWrap/GCM/NoPadding". As Maarten pointed out, logically this operation should configure the Cipher in WRAP_MODE.

RSA Public key getting changed after converting to RSAPublicKeySpec

I have a RSA public key material as byte array (the key format is PKCS1). I create a PublicKey object out of it using RSAPublicKeySpec as shown below.
public Key retrievePubKey(byte[] derStuff){ // der stuff is my key material
KeySpec ks = null;
Key wrapKey = null;
try {
DerInputStream dis = new DerInputStream(derStuff);
DerValue val = dis.getDerValue();
BigInteger first = val.getData().getBigInteger();
BigInteger second = val.getData().getBigInteger();
ks = new RSAPublicKeySpec(first, second);
KeyFactory kf = KeyFactory.getInstance("RSA", "IBMJCE");
wrapKey = kf.generatePublic(ks);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return wrapKey;
}
Then I cast the Key to PublicKey
PublicKey pubKey = (PublicKey) mainObj.retrievePubKey(keyMaterial);
Now when I print the key material inside the pubKey, I get a different key material.
original key material
3082010a0282010100ab7f161c0042496ccd6c6d4dadb919973435357776003acf54b7af1e440afb80b64a8755f8002cfeba6b184540a2d66086d74648346d75b8d71812b205387c0f6583bc4d7dc7ec114f3b176b7957c422e7d03fc6267fa2a6f89b9bee9e60a1d7c2d833e5a5f4bb0b1434f4e795a41100f8aa214900df8b65089f98135b1c67b701675abdbc7d5721aac9d14a7f081fcec80b64e8a0ecc8295353c795328abf70e1b42e7bb8b7f4e8ac8c810cdb66e3d21126eba8da7d0ca34142cb76f91f013da809e9c1b7ae64c54130fbc21d80e9c2cb06c5c8d7cce8946a9ac99b1c2815c3612a29a82d73a1f99374fe30e54951662a6eda29c6fc411335d5dc7426b0f6050203010001
Converted key material
When I do byteArrayToHexString(pubKey.getEncoded());
30820122300D06092A864886F70D01010105000382010F003082010A0282010100AB7F161C0042496CCD6C6D4DADB919973435357776003ACF54B7AF1E440AFB80B64A8755F8002CFEBA6B184540A2D66086D74648346D75B8D71812B205387C0F6583BC4D7DC7EC114F3B176B7957C422E7D03FC6267FA2A6F89B9BEE9E60A1D7C2D833E5A5F4BB0B1434F4E795A41100F8AA214900DF8B65089F98135B1C67B701675ABDBC7D5721AAC9D14A7F081FCEC80B64E8A0ECC8295353C795328ABF70E1B42E7BB8B7F4E8AC8C810CDB66E3D21126EBA8DA7D0CA34142CB76F91F013DA809E9C1B7AE64C54130FBC21D80E9C2CB06C5C8D7CCE8946A9AC99B1C2815C3612A29A82D73A1F99374FE30E54951662A6EDA29C6FC411335D5DC7426B0F6050203010001
Then I try to verify the signature using the new PublicKey pubKey - but it fails
The validityIndicator is false
Signature signerVerify = Signature.getInstance("SHA256withRSA", "IBMJCE"); // tried with "RSA" - Failing
signerVerify.initVerify(pubKey);
signerVerify.update(dataToBeSigned);
boolean validityIndicator = signerVerify.verify(signature);
The dataToBeSigned and keyMaterial are taken from OASIS test cases
I've tried several other methods (see here) explained on stackoverflow but none is working.

Storing a hmac key in Android keystore

I am using the below code to create a hmac key and returning it as a string.
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("HmacSHA256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
SecretKey key = keyGen.generateKey();
byte[] encoded = key.getEncoded();
String s=Base64.encodeToString(encoded, Base64.DEFAULT);
Log.i("Hmac key before encrypt",s);
try {
KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(null, null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keystore.getEntry("temp", null);
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherBytes = cipher.doFinal(encoded);
return Base64.encodeToString(cipherBytes,Base64.DEFAULT);
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
How can I store this in the android keystore?. I have tried using the below code:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection("test".toCharArray());
keyStore.setEntry("key1",hmacKey,param);
I get an errors no matter what format hmacKey is in: String/Bytes or javax.crypto.SecretKey. Below are the errors:
In case of passing Key hmacKey:
Wrong 2nd argument type. Found: 'java.security.Key', required: 'java.security.KeyStore.Entry'
Same in cases where I pass a string or byte array.
If I typecast the parameter to java.security.KeyStore.Entry, it still doesn't work.
Is this the correct way of doing so? Can anyone give pointers as to how the HMAC key can be stored in the keystore using an alias. How can convert the hmack key to java.security.KeyStore.Entry format?
The Android key store was created to allow you to use asymmetric keys and symmetric keys outside your application code. As specified in the training material:
Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations. If the app's process is compromised, the attacker may be able to use the app's keys but will not be able to extract their key material (for example, to be used outside of the Android device).
So the idea of generating the key inside the application code - and thus outside the key store - is not a good idea. How to generate a secret key inside the key store is defined for HMAC keys in the API for the KeyGenParameterSpec class:
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore");
keyGenerator.initialize(
new KeyGenParameterSpec.Builder("key2", KeyProperties.PURPOSE_SIGN).build());
SecretKey key = keyGenerator.generateKey();
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
...
// The key can also be obtained from the Android Keystore any time as follows:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
key = (SecretKey) keyStore.getKey("key2", null);
Other key types can be found in the KeyProperties class

Common Encryption algorithm for Rails and Java

I am going to integrate two web applications written in different platforms (Java and Ruby),
I have to use common encryption algorithm for password in both application.
Is there any common encryption/decryption algorithm for both? If yes, please mention any useful link or any example.
It would be highly appreciated. Thanks in advance
In addition during my digging out it I found,
I have used Base64 with DES in both, interesting thing is that Characters and special characters give me same result in both but as i adding any number like (1,2,3), half of result is same and half encryption is something different.
*Ruby Code
require 'openssl'
require 'base64'
c = OpenSSL::Cipher::Cipher.new("des")
c.encrypt
c.key ="REPPIFY_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
e = c.update("ankit#123")
e << c.final
puts Base64.encode64(e)
Output: Cbe9GslMs8mh33jAOD9qsw==
*Java Code
I am defining only encryption method here:-
public static String encryptPassword(String pass) {
public static final String DESKEY = "REPPIFY_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
System.out.println("Here is my password = "+pass);
DESKeySpec keySpec = null;
SecretKeyFactory keyFactory = null;
SecretKey key = null;
Cipher cipher = null;
BASE64Encoder base64encoder = new BASE64Encoder();
byte[] cleartext = null;
String encrypedPwd = null;
String pass = "ankit#123";
try {
keySpec = new DESKeySpec(DESKEY.getBytes("UTF8"));
keyFactory = SecretKeyFactory.getInstance("DES");
key = keyFactory.generateSecret(keySpec);
if(pass!=null) {
cleartext = pass.getBytes("UTF8");
cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
encrypedPwd = base64encoder.encode(cipher.doFinal(cleartext));
}
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} // cipher is not thread safe
catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
System.out.println("Here I am printing encrypted pwd = "+encrypedPwd);
return encrypedPwd;
}
Output in Java :- Cbe9GslMs8mWn9yTmZrUiw==
Well, in the Ruby world, I'd recommend BCrypt, which is also favored by popular authentication plugins like Devise. I'm not very familiar with Java but a quick search suggests that there's BCrypt implementation in Java too:
http://www.mindrot.org/projects/jBCrypt/
EDIT - BCrypt is 1-way encryption, mainly for use in hashing passwords. If you are looking for something that will encrypt and decrypt then you'll have to look at something else. Seeing as you mentioned it's for passwords I'd suggest you only want 1-way encryption though.
I got the answer...just change a following line in ruby code and then you can use base64 decoder with DES in both:
c = OpenSSL::Cipher::Cipher.new("DES-ECB")
require 'openssl'
require 'base64'
c = OpenSSL::Cipher::Cipher.new("DES-ECB")
c.encrypt
c.key ="REPPIFY_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
e = c.update("ankit#123")
e << c.final
puts Base64.encode64(e)

BadPaddingException: Given final block not properly padded

I have a private key file encripted with DES/ECB/PKCS5Padding (56 bit DES key generated by a secret phrase) and I want to decrypt it.
I don't know why, but everytime I try to decript, the method doFinal of my cipher class is throwing this error:
javax.crypto.BadPaddingException: Given final block not properly
padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.DESCipher.engineDoFinal(DashoA13*..) at
javax.crypto.Cipher.doFinal(DashoA13*..) at...
Here is my code:
public static PrivateKey readPrivateKeyFromFile(File file, String chaveSecreta) {
try {
SecureRandom r = new SecureRandom(chaveSecreta.getBytes());
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
keyGen.init(56, r);
Key key = keyGen.generateKey();
byte[] privateKeyBytes = decryptPKFile(file, key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = null;
try {
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException e) {
JOptionPane.showMessageDialog(null, "Erro 01, tente mais tarde");
}
return privateKey;
} catch (NoSuchAlgorithmException e) {
JOptionPane.showMessageDialog(null, "Erro 02, tente mais tarde");
}
return null;
}
public static byte[] decryptPKFile(File file, Key key){
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
byte[] cipherText = readBytes(file);
cipher.init(Cipher.DECRYPT_MODE, key);
System.out.println(cipher);
System.out.println(cipherText);
byte[] text = cipher.doFinal(cipherText);
return text;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
public static byte[] readBytes(File file) {
try {
FileInputStream fs = new FileInputStream(file);
byte content[] = new byte[(int) file.length()];
fs.read(content);
return content;
} catch (FileNotFoundException e) {
System.out.println("Arquivo não encontrado!");
e.printStackTrace();
} catch (IOException ioe) {
System.out.println("Erro ao ler arquivo!");
ioe.printStackTrace();
}
return null;
}
Any syggestions?
You're trying to decrypt ciphertext with a random number generator created using a specific seed. However, you don't specify the algorithm, and the algorithm may change internally as well. Android is even known to generate a fully random value instead for some versions.
You need to use a SecretKeyFactory not a KeyGenerator. And you will of course need the 8-byte key data. The only way to retrieve this in your case is to find the SecureRandom algorithm/implementation before and re-calculate the key.
Now any ciphertext will decrypt with any key. DES ECB only provides (some sort of) confidentiality, not integrity. The problem is that it will decrypt into garbage. Now if you try to remove the padding from garbage you will likely get a padding error.
If you're "lucky" - once in about 256 times - you will get a result. This happens when the decrypted block ends with 01 or 0202, that's valid padding. The result will - of course - be garbage as well, but it will not end with a BadPaddingException. In your case the SecureRandom instance is likely to return the same incorrect value over and over though, so this may never happen.
In the future, please use PBKDF2 and feed it the encoded password. Clearly note the character encoding used, Java SE uses the lowest 8 bits of the char array. Never ever use String.getBytes() as the default encoding may differ between systems.

Categories