I need to implement AES Encryption Algorithm in Cryptographic Message Syntax (CMS) standard to encrypt my data in Windows Universal App (found reference here). I have it implemented on Java using Bouncy Castle library using the following code(I need the same functionality in C# UWP):
private static final ASN1ObjectIdentifier CMS_ENCRYPTION_ALGO = CMSAlgorithm.AES256_CBC;
private byte[] encrypt(byte[] key, byte[] dataToBeEncrypted) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, CMSException {
final KeySpec keySpec = new X509EncodedKeySpec(key);
final KeyFactory factory = KeyFactory.getInstance("RSA");
final PublicKey publicKey = factory.generatePublic(keySpec);
final SubjectKeyIdentifier subjectKeyIdentifier = new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey);
final RecipientInfoGenerator recipientInfoGenerator = new JceKeyTransRecipientInfoGenerator(subjectKeyIdentifier.getEncoded(), publicKey);
final CMSEnvelopedDataGenerator generator = new CMSEnvelopedDataGenerator();
generator.addRecipientInfoGenerator(recipientInfoGenerator);
final OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMS_ENCRYPTION_ALGO).build();
final CMSProcessableByteArray content = new CMSProcessableByteArray(dataToBeEncrypted);
final CMSEnvelopedData envelopedData = generator.generate(content, encryptor);
return envelopedData.toASN1Structure().getEncoded(ASN1Encoding.DER);
}
Now I have Referenced Bouncy Castle V 1.8.1 in my UWP App, but I found many differences (some libraries used in Java but not exist in Windows) and couldn't implement such functionality in C#.
So kindly either guide me to implement the same using native UWP Cryptography Library Windows.Security.Cryptography (Preferred),
Or tell me how can I implement same functionality using Bouncy Castle 1.8.1 in C# UWP app.
Update:
Based on the following diagram from here, I understand that the required steps are:
1- Get the data and generate Symmetric Key to encrypt the data using algorithm AesCbcPkcs7.
2- Encrypt Symmetric Key using the public key
3- Generate Digitally enveloped message.
So I did the first two steps based on my understanding using the following c# code (Please correct me if I'm wrong) and I need help to do the third step:
public string EncryptAndEnvelope(string openText, string p_key)
{
// Step 1 Get the data and generate Symmetric Key to encrypt the data using algorithm AesCbcPkcs7
IBuffer cBuffer = CryptographicBuffer.GenerateRandom(32);
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
CryptographicKey m_key = provider.CreateSymmetricKey(cBuffer);
IBuffer bufferMsg = CryptographicBuffer.ConvertStringToBinary(AsciiToString(StringToAscii(openText)), BinaryStringEncoding.Utf8);
IBuffer bufferEncrypt = CryptographicEngine.Encrypt(m_key, bufferMsg, null);
// Step 2 Encrypt Symmetric Key using the public key
IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(p_key);
AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey ckey = asym.ImportPublicKey(publicKey, CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
IBuffer cbufferEncrypt = CryptographicEngine.Encrypt(ckey, cBuffer, null);
// Step 3 Generate Digitally enveloped message
// I need help here
}
private byte[] StringToAscii(string s)
{
byte[] retval = new byte[s.Length];
for (int ix = 0; ix < s.Length; ++ix)
{
char ch = s[ix];
if (ch <= 0x7f) retval[ix] = (byte)ch;
else retval[ix] = (byte)'?';
}
return retval;
}
private string AsciiToString(byte[] bytes)
{
return string.Concat(bytes.Select(b => b <= 0x7f ? (char)b : '?'));
}
Note: While I was looking for solution, I've found that the answer is available using the library System.Security.Cryptography
(but it is not supported in Universal Apps) and I'm pretty sure that
the implementation is available using Bouncy Castle (there are
tons of documentation for Java but unfortunately there is no
documentation at all for C#).
Related
I am trying to implement gost 28147-89 algorithm for encrypting and decrypting string.
In the bouncycastle documentation I didn't understand how to implement gost 28147. How can I make a simple class which encrypts and decrypts a string using the gost 28147-89 algorithm?
Quoting from GOST28147Test.java (basically an example class from the bouncy castle people for exactly that encryption scheme):
key = new SecretKeySpec(keyBytes, "GOST28147");
in = Cipher.getInstance("GOST28147/ECB/NoPadding", "BC");
out = Cipher.getInstance("GOST28147/ECB/NoPadding", "BC");
out.init(Cipher.ENCRYPT_MODE, key);
in.init(Cipher.DECRYPT_MODE, key);
//
// encryption pass
//
bOut = new ByteArrayOutputStream();
cOut = new CipherOutputStream(bOut, out);
for (int i = 0; i != input.length / 2; i++)
{
cOut.write(input[i]);
}
And so on ...
I am writing a test harness in java for a program relating to the ikev2 protocol. As part of this i need to be able to calculate an ECDSA signature (specifically using the NIST P-256 curve).
RFC 4754 Describes the the use of ECDSA in IKEv2 and helpfully provides a set of test vectors (Including for the p256 curve that i need).
I am trying to run the ECDSA-256 Test Vector values (Section 8.1 in the RFC) through java's ECDSA signature implementation using the following code:
//"abc" for the input
byte[] input = { 0x61, 0x62, 0x63 };
//Ugly way of getting the ECParameterSpec for the P-256 curve by name as opposed to specifying all the parameters manually.
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1");
kpg.initialize(kpgparams);
ECParameterSpec params = ((ECPublicKey) kpg.generateKeyPair().getPublic()).getParams();
//Create the static private key W from the Test Vector
ECPrivateKeySpec static_privates = new ECPrivateKeySpec(new BigInteger("DC51D3866A15BACDE33D96F992FCA99DA7E6EF0934E7097559C27F1614C88A7F", 16), params);
KeyFactory kf = KeyFactory.getInstance("EC");
ECPrivateKey spriv = (ECPrivateKey) kf.generatePrivate(static_privates);
//Perfrom ECDSA signature of the data with SHA-256 as the hash algorithm
Signature dsa = Signature.getInstance("SHA256withECDSA");
dsa.initSign(spriv);
dsa.update(input);
byte[] output = dsa.sign();
System.out.println("Result: " + new BigInteger(1, output).toString(16));
The result should be:
CB28E099 9B9C7715 FD0A80D8 E47A7707 9716CBBF 917DD72E
97566EA1 C066957C 86FA3BB4 E26CAD5B F90B7F81 899256CE 7594BB1E A0C89212
748BFF3B 3D5B0315
Instead I get:
30460221 00dd9131 edeb5efd c5e718df c8a7ab2d 5532b85b 7d4c012a e5a4e90c 3b824ab5 d7022100 9a8a2b12 9e10a2ff 7066ff79 89aa73d5 ba37c868 5ec36517 216e2e43 ffa876d7
I know that the length difference is due to Java ASN.1 Encoding the signature. However, the rest of it is completely wrong and I'm stumped as to why.
Any help or advice would be greatly appreciated!
P.S I am not a ECDSA or Java crypto expert so it is probably a stupid mistake I am making
I'm guessing that each time you run your program, you get a different signature value for the same plaintext (to-be-signed) input.
ECDSA specifies that a random ephemeral ECDSA private key be generated per signature. To that end, Signature.getInstance("SHA256withECDSA") doesn't let you specify an ephemeral key (this is a good thing, to prevent many a self shot in the foot!). Instead, it gets its own SecureRandom instance that will make your output nondeterministic.
This probably means you can't use JCE (Signature.getInstance()) for test vector validation.
What you could do is extend SecureRandom in a way that it returns deterministic data. Obviously you shouldn't use this in a real deployment:
public class FixedSecureRandom extends SecureRandom {
private static boolean debug = false;
private static final long serialVersionUID = 1L;
public FixedSecureRandom() { }
private int nextBytesIndex = 0;
private byte[] nextBytesValues = null;
public void setBytes(byte[] values) {
this.nextBytesValues = values;
}
public void nextBytes(byte[] b) {
if (nextBytesValues==null) {
super.nextBytes(b);
} else if (nextBytesValues.length==0) {
super.nextBytes(b);
} else {
for (int i=0; i<b.length; i++) {
b[i] = nextBytesValues[nextBytesIndex];
nextBytesIndex = (nextBytesIndex + 1) % nextBytesValues.length;
}
}
}
}
Phew. Ok now you have a SecureRandom class that returns you some number of known bytes, then falls back to a real SecureRandom after that. I'll say it again (excuse the shouting) - DO NOT USE THIS IN PRODUCTION!
Next you'll need to use a ECDSA implementation that lets you specify your own SecureRandom. You can use BouncyCastle's ECDSASigner for this purpose. Except here you're going to give it your own bootlegged FixedSecureRandom, so that when it calls secureRandom.getBytes(), it gets the bytes you want it to. This lets you control the ephemeral key to match that specified in the test vectors. You may need to massage the actual bytes (eg. add zero pre-padding) to match what ECDSASigner is going to request.
ECPrivateKeyParameters ecPriv = ...; // this is the user's EC private key (not ephemeral)
FixedSecureRandom fsr_k = new FixedSecureRandom();
fsr_k.setBytes(tempKeyK);
ECDSASigner signer = new ECDSASigner();
ParametersWithRandom ecdsaprivrand = new ParametersWithRandom(ecPriv, fsr_k);
signer.init(true, ecdsaprivrand);
Note that BC's ECDSASigner implements only the EC signature part, not the hashing. You'll still need to do your own hashing (assuming your input data is in data):
Digest md = new SHA256Digest()
md.reset();
md.update(data, 0, data.length);
byte[] hash = new byte[md.getDigestSize()];
md.doFinal(hash, 0);
before you create the ECDSA signature:
BigInteger[] sig = signer.generateSignature(hash);
Finally, this BigInteger[] (should be length==2) are the (r,s) values. You'll need to ASN.1 DER-encode it, which should give you the droids bytes you're looking for.
here's my complete test following tsechin's solution using BouncyCastle but sticking to good old JCA API:
byte[] input = { 0x61, 0x62, 0x63 };
//Create the static private key W from the Test Vector
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
org.bouncycastle.jce.spec.ECPrivateKeySpec privateKeySpec = new org.bouncycastle.jce.spec.ECPrivateKeySpec(new BigInteger("DC51D3866A15BACDE33D96F992FCA99DA7E6EF0934E7097559C27F1614C88A7F", 16), parameterSpec);
KeyFactory kf = KeyFactory.getInstance("EC");
ECPrivateKey spriv = (ECPrivateKey) kf.generatePrivate(privateKeySpec);
//Perfrom ECDSA signature of the data with SHA-256 as the hash algorithm
Signature dsa = Signature.getInstance("SHA256withECDSA", "BC");
FixedSecureRandom random = new FixedSecureRandom();
random.setBytes(Hex.decode("9E56F509196784D963D1C0A401510EE7ADA3DCC5DEE04B154BF61AF1D5A6DECE"));
dsa.initSign(spriv, random);
dsa.update(input);
byte[] output = dsa.sign();
// compare the signature with the expected reference values
ASN1Sequence sequence = ASN1Sequence.getInstance(output);
DERInteger r = (DERInteger) sequence.getObjectAt(0);
DERInteger s = (DERInteger) sequence.getObjectAt(1);
Assert.assertEquals(r.getValue(), new BigInteger("CB28E0999B9C7715FD0A80D8E47A77079716CBBF917DD72E97566EA1C066957C", 16));
Assert.assertEquals(s.getValue(), new BigInteger("86FA3BB4E26CAD5BF90B7F81899256CE7594BB1EA0C89212748BFF3B3D5B0315", 16));
I have previously used a RSACryptoServiceProvider in C# to encrypt some data, and now I have to replicate this encryption in an Android program. I want my Android program to generate the same result as I got in my C# program.
Public Key:
<RSAKeyValue>
<Modulus>zz4qdc39y1BHyJgVXUkINJSbsUd1ZJPISyE9nNGjqgR+ZO1a4cE3ViVCSZCw+6dBdVMFNjzZPBxl0mT57GIq7rcuoT0scesZgxOftbMasPbxp0BGrh3HTpbBMJdCopgcYV98CZERakb8Pgbb0ne/DiW9Aq0kfTBE02/iEHRNuqMNfo1GFo55m0OKbxVoM6UBb8AITQ6lbdvfCgeIvMzRlVrHCwxUNrrX5cS6gurEfJ8Da+prKQmwWpFCkwDkPWje2W+bTSPUc9l6Ads0UimYE5sGs4Zsfz6Eocz4rJjR+qCiB8qt6HtdyjKo0auqYzyXIjdRv2950flc9tOh5bRlQQ==
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
Java Encryption Program:
byte[] modulusBytes = Base64.decode(Modoutput.getBytes("UTF-8"),
Base64.DEFAULT);
byte[] exponentBytes = Base64.decode(Expoutput.getBytes("UTF-8"),
Base64.DEFAULT);
BigInteger e = new BigInteger(1, exponentBytes);
BigInteger m = new BigInteger(1, modulusBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKeyn = fact.generatePublic(keySpec);
Log.i("Publickey", pubKeyn.toString());
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pubKeyn);
byte[] encryptedByteData = cipher.doFinal(byteData);
String outputEncrypted = Base64.encodeToString(encryptedByteData,
Base64.NO_WRAP);
Log.i("Encrypteddata", outputEncrypted);
I tried the above code but it gives an entirely different output from C#. Can anyone tell me what is wrong with my code? Thanks in advance.
Edit: As requested, here is the C# code for which I am trying to replicate the encrypted output in Java:
public static string EncryptText(string text, int keySize,
string publicKeyXml) {
var encrypted = Encrypt(Encoding.UTF8.GetBytes(text), keySize,
publicKeyXml);
return Convert.ToBase64String(encrypted);
}
public static byte[] Encrypt(byte[] data, int keySize, string publicKeyXml) {
if (data == null || data.Length == 0)
throw new ArgumentException("Data are empty", "data");
int maxLength = GetMaxDataLength(keySize);
if (data.Length > maxLength)
throw new ArgumentException(String.Format(
"Maximum data length is {0}", maxLength), "data");
if (!IsKeySizeValid(keySize))
throw new ArgumentException("Key size is not valid", "keySize");
if (String.IsNullOrEmpty(publicKeyXml))
throw new ArgumentException("Key is null or empty", "publicKeyXml");
using (var provider = new RSACryptoServiceProvider(keySize)) {
provider.FromXmlString(publicKeyXml);
return provider.Encrypt(data, _optimalAsymmetricEncryptionPadding);
}
}
Encryption by definition tries to hide all information about the plain text. This includes information about identical plain text. To do this it uses some kind of random within the various padding modes (e.g. PKCS#1 v1.5 compatible padding or OAEP padding for RSA). So speaking from a cryptographic standpoint, the implementation is broken if you ever get an identical result.
The method to check if the ciphertext is correct is by decrypting it using the private key. If that results in the plaintext you started with then your implementation is correct.
[EDIT] Note that you are using OAEP encryption in the C# code, while Java uses the PKCS#1 v1.5 compatible scheme by default. You should use "RSA/None/OAEPWithSHA1AndMGF1Padding" or "RSA/ECB/OAEPWithSHA1AndMGF1Padding". If it is not available add the Bouncy Castle provider.
I am developing Distributed digital signature that signs a document and send it through network to the Application Server.I am using socket programming in java to do it. I think the public key should be encoded or compressed i.e the x and y values are somehow represented as a single binary data and saved in a public registry or network.But i don't know how to do it in java.
// I have class like this
public class CryptoSystem{
EllipticCurve ec = new EllipticCurve(new P192());
//-------------------
//--------------------
public ECKeyPair generatekeyPair()
{
return ECKeyPair(ec);
}
}
// i don't think i have problem in the above
CryptoSystem crypto = new CryptoSystem();
ECKeyPair keyPair = crypto.generateKeyPair();
BigInteger prvKey = keyPair.getPrivateKey();
ECPoint pubKey = keyPair.getPublicKey();
// recommend me here to compress and send it the public key to a shared network.
I want to know how to encode the public key and domain parameters, so that the verifier of the signature will decode it to use it.because when you send them over the network to the verifier u gonna have to encode the as a single byte array.i am no using Bouncy Castle Provider. The whole implementation of ECDSA algorithm is my project
Elliptic curve points are almost always encoded using the encoding specified in X9.62.
It is optional to use point compression. It is trivial to encode using point compression, but decoding a compressed point needs a bit more work, so unless you really need to save the extra bytes, I would not bother. Let me know if you need it, and I will add the details. You can recognize X9.62 encoded points with point compression by the first byte, which will be 0x02 or 0x03.
Encoding without point compression is really simple: start with a 0x04 (to indicate no compression). Then follow with first the x coordinate, then the y coordinate, both zero-padded on the left up to the size in bytes of the field:
int qLength = (q.bitLength()+7)/8;
byte[] xArr = toUnsignedByteArray(x);
byte[] yArr = toUnsignedByteArray(y);
byte[] res = new byte[1+2*qLength];
res[0] = 0x04;
System.arraycopy(xArr, 0, res, qLength - xArr.length, xArr.length);
System.arraycopy(yArr, 0, res, 2* qLength - yArr.length, nLength);
Decoding this is of course trivial.
I'm pretty sure that the BC implementation uses X9.63 encoding, so these would be rather standardized encodings. You will need to add the Bouncy Castle provider to your JRE (Security.addProvider(new BouncyCastleProvider()), see the bouncy documentation.
public static void showECKeyEncodings() {
try {
KeyPairGenerator kp = KeyPairGenerator.getInstance("ECDSA");
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable
.getParameterSpec("prime192v1");
kp.initialize(ecSpec);
KeyPair keyPair = kp.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
byte[] encodedPrivKey = privKey.getEncoded();
System.out.println(toHex(encodedPrivKey));
PublicKey pubKey = keyPair.getPublic();
byte[] encodedPubKey = pubKey.getEncoded();
System.out.println(toHex(encodedPubKey));
KeyFactory kf = KeyFactory.getInstance("ECDSA");
PublicKey pubKey2 = kf.generatePublic(new X509EncodedKeySpec(encodedPubKey));
if (Arrays.equals(pubKey2.getEncoded(), encodedPubKey)) {
System.out.println("That worked for the public key");
}
PrivateKey privKey2 = kf.generatePrivate(new PKCS8EncodedKeySpec(encodedPrivKey));
if (Arrays.equals(privKey2.getEncoded(), encodedPrivKey)) {
System.out.println("That worked for the private key");
}
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
I have keys created in Java. The private key is PKCS#8 encrypted, in PEM string.
Here is an example of using the private key with M2Crypto in Python:
from M2Crypto import EVP, BIO
privpem = "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIICoTAbBgoqhkiG9w0BDAEDMA0ECFavEvdkv3fEAgEUBIICgAWvHvH6OktLiaaqo9v+X6XEuY3M\nZr465VmZWzP9nsbTqwSKQQjseiD/rWAxK7RS+V+hit5ZxlNRAUbkg0kwl8SRNX3v6q8noJtcB0OY\ndBEuNJDmWHMHh8qcnfRYc9WXPPmWdjQM2AkfZNfNOxHVlOMhancScy6P4h3Flri9VyUE8w2/zZqK\nBAd2w39V7gprCQXnnNenNuvr4p8MjsdBm8jh00o2HJzN0I6u+9s7M3qLXxwxNepptgU6Qt6eKHi6\njpsV/musVaohLhFMFAzQ87FeGvz/W8dyS9BtAKMRSuDu/QdWIJMRNKkPT0Tt1243V3tzXVXLjz0u\nm/FX6kfxL8r+eGtTr6NKTG75TJfooQzN/v08OEbmvYD/mfptmZ7uKezOGxDmgynn1Au7T/OxKFhx\nWZHpb9OFPIU0uiriUeyY9sbDVJ054zQ/Zd5+iaIjX5RsLoB4J+pfr4HuiVIZVj+Ss2rnPsOY3SjM\ntbHIFp/fLr/HODcDA5eYADRGpBIL9//Ejgzd7OqpU0mdajzZHcMTjeXfWB0cc769bFyHb3Ju1zNO\ng4gNN1H1kOMAXMF7p6r25f6v1BRS6bQyyiFz7Hs7h7JBylbBAgQJgZvv9Ea3XTMy+DIPMdepqu9M\nXazmmYJCtdLAfLBybWsfSBU5K6Pm6+Bwt6mPsuvYQBrP3h84BDRlbkntxUgaWmTB4dkmzhMS3gsY\nWmHGb1N+rn7xLoA70a3U/dUlI7lPkWBx9Sz7n8JlH3cM6jJUmUbmbAgHiyQkZ2mf6qo9qlnhOLvl\nFiG6AY+wpu4mzM6a4BiGMNG9D5rnNyD16K+p41LsliI/M5C36PKeMQbwjJKjmlmWDX0=\n-----END ENCRYPTED PRIVATE KEY-----\n"
msg = "This is a message."
privkeybio = BIO.MemoryBuffer(privpem)
privkey = EVP.load_key_bio(privkeybio) #pw: 123456
privkey.sign_init()
privkey.sign_update(msg)
print privkey.sign_final().encode('base64')
And here is example of how I can use the PEM (with header and footer stripped off) in Java:
String msg = "This is a message.";
String privpem = "MIICoTAbBgoqhkiG9w0BDAEDMA0ECFavEvdkv3fEAgEUBIICgAWvHvH6OktLiaaqo9v+X6XEuY3M\nZr465VmZWzP9nsbTqwSKQQjseiD/rWAxK7RS+V+hit5ZxlNRAUbkg0kwl8SRNX3v6q8noJtcB0OY\ndBEuNJDmWHMHh8qcnfRYc9WXPPmWdjQM2AkfZNfNOxHVlOMhancScy6P4h3Flri9VyUE8w2/zZqK\nBAd2w39V7gprCQXnnNenNuvr4p8MjsdBm8jh00o2HJzN0I6u+9s7M3qLXxwxNepptgU6Qt6eKHi6\njpsV/musVaohLhFMFAzQ87FeGvz/W8dyS9BtAKMRSuDu/QdWIJMRNKkPT0Tt1243V3tzXVXLjz0u\nm/FX6kfxL8r+eGtTr6NKTG75TJfooQzN/v08OEbmvYD/mfptmZ7uKezOGxDmgynn1Au7T/OxKFhx\nWZHpb9OFPIU0uiriUeyY9sbDVJ054zQ/Zd5+iaIjX5RsLoB4J+pfr4HuiVIZVj+Ss2rnPsOY3SjM\ntbHIFp/fLr/HODcDA5eYADRGpBIL9//Ejgzd7OqpU0mdajzZHcMTjeXfWB0cc769bFyHb3Ju1zNO\ng4gNN1H1kOMAXMF7p6r25f6v1BRS6bQyyiFz7Hs7h7JBylbBAgQJgZvv9Ea3XTMy+DIPMdepqu9M\nXazmmYJCtdLAfLBybWsfSBU5K6Pm6+Bwt6mPsuvYQBrP3h84BDRlbkntxUgaWmTB4dkmzhMS3gsY\nWmHGb1N+rn7xLoA70a3U/dUlI7lPkWBx9Sz7n8JlH3cM6jJUmUbmbAgHiyQkZ2mf6qo9qlnhOLvl\nFiG6AY+wpu4mzM6a4BiGMNG9D5rnNyD16K+p41LsliI/M5C36PKeMQbwjJKjmlmWDX0=";
byte [] privkeybytes = Base64.decode(privpem);
EncryptedPrivateKeyInfo encprivki = new EncryptedPrivateKeyInfo(privkeybytes);
Cipher cipher = Cipher.getInstance(encprivki.getAlgName());
PBEKeySpec pbeKeySpec = new PBEKeySpec("123456".toCharArray());
SecretKeyFactory secFac = SecretKeyFactory.getInstance(encprivki.getAlgName());
Key pbeKey = secFac.generateSecret(pbeKeySpec);
AlgorithmParameters algParams = encprivki.getAlgParameters();
cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
KeySpec pkcs8KeySpec = encprivki.getKeySpec(cipher);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pk = kf.generatePrivate(pkcs8KeySpec);
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(pk);
sig.update(msg.getBytes("UTF8"));
byte[] signatureBytes = sig.sign();
String b = Base64.encodeBytes(signatureBytes, Base64.DO_BREAK_LINES);
System.out.println(b); // Display the string.
How would this be done in iOS? I have looked at the CryptoExercise, in particular the SecKeyWrapper, but there is lots going on there, and it's beyond me.
I am not personally going to be doing the iOS development, but I need some code to give to the developer to at least show more or less how to do it. The developer is more a UI type and not familiar with crypto. (Neither am I but that is a different story...)
And while we're at it, how to verify a signature against a string public key PEM? I won't put the Java and Python examples here as they are pretty straight forward.
I had the same problem last week. The CommonCrypt library on iOS is very nice for symmetric key encryption, but it's just too much hassle dealing with the keyring to do simple public key things. After spending about half an hour poking at it I just included OpenSSL. OpenSSL-Xcode made this trivial to set up - just drop the project and the OpenSSL tarball in, set your target to link with libssl, and you're good to go.
The OpenSSL code looks nearly the same as the M2Crypto one.