This repository has been archived by the owner on Jul 11, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from ayiemba/Dev
Added SecurityCredential Helper (Takes in certificate and initiator password then returns sec
- Loading branch information
Showing
6 changed files
with
333 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using System; | ||
using System.IO; | ||
using System.Security.Cryptography; | ||
using System.Security.Cryptography.X509Certificates; | ||
using System.Text; | ||
|
||
namespace MpesaLib.Helpers | ||
{ | ||
|
||
/* | ||
M-Pesa Core authenticates a transaction by decrypting the security credentials. | ||
Security credentials are generated by encrypting the base64 encoded initiator password with M-Pesa’s public key, | ||
a X509 certificate. | ||
The algorithm for generating security credentials is as follows: | ||
Write the unencrypted password into a byte array. | ||
Encrypt the array with the M-Pesa public key certificate. Use the RSA algorithm, | ||
and use PKCS #1.5 padding (not OAEP), and add the result to the encrypted stream. | ||
Convert the resulting encrypted byte array into a string using base64 encoding. | ||
The resulting base64 encoded string is the security credential. | ||
*/ | ||
|
||
|
||
/// <summary> | ||
/// Encrypt password helper class for MpesaLib | ||
/// </summary> | ||
public static class Credentials | ||
{ | ||
/// <summary> | ||
/// Encrypts Mpesa API Security Credential password | ||
/// </summary> | ||
/// <param name="certificatePath"></param> | ||
/// <param name="password"></param> | ||
/// <returns></returns> | ||
public static string EncryptPassword(string certificatePath, string password) | ||
{ | ||
|
||
//get certificate data in bytes | ||
var data = ReadFile(certificatePath); | ||
|
||
//var rsa3 = new RSACryptoServiceProvider(); | ||
|
||
X509Certificate2 x509 = new X509Certificate2(data); | ||
|
||
RSA publicprovider = (RSA)x509.PublicKey.Key; | ||
|
||
#if !NETSTANDARD2_0 | ||
var key1 = publicprovider.ToXmlString(false); | ||
#else | ||
var key1 = publicprovider.ToXmlString2(false); | ||
#endif | ||
|
||
var data2 = Encoding.UTF8.GetBytes(password); | ||
|
||
using (var rsa2 = new RSACryptoServiceProvider()) | ||
{ | ||
try | ||
{ | ||
rsa2.FromXmlString2(key1); | ||
var encryptedData = rsa2.Encrypt(data2, false); | ||
var base64Encrypted = Convert.ToBase64String(encryptedData); | ||
return base64Encrypted; | ||
} | ||
finally | ||
{ | ||
rsa2.PersistKeyInCsp = false; | ||
} | ||
} | ||
} | ||
|
||
//Reads a certificate file file. | ||
private static byte[] ReadFile(string fileName) | ||
{ | ||
FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read); | ||
int size = (int)f.Length; | ||
byte[] data = new byte[size]; | ||
size = f.Read(data, 0, size); | ||
f.Close(); | ||
return data; | ||
} | ||
|
||
|
||
|
||
} | ||
} |
149 changes: 149 additions & 0 deletions
149
src/MpesaLib/Helpers/RSACryptoServiceProviderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
using System; | ||
using System.Security.Cryptography; | ||
using System.Xml; | ||
|
||
namespace MpesaLib.Helpers | ||
{ | ||
/// <summary> | ||
/// RSACryptoServiceProvider Extensions | ||
/// </summary> | ||
public static class RSACryptoServiceProviderExtensions | ||
{ | ||
/// <summary> | ||
/// Imports the specified XML String into the crypto service provider | ||
/// </summary> | ||
/// <remarks> | ||
/// .NET Core 2.0 doesn't provide an implementation of RSACryptoServiceProvider.FromXmlString/ToXmlString, so we have to do it ourselves. | ||
/// Source: https://gist.github.com/Jargon64/5b172c452827e15b21882f1d76a94be4/ | ||
/// </remarks> | ||
public static void FromXmlString2(this RSACryptoServiceProvider rsa, string xmlString) | ||
{ | ||
#if !NETSTANDARD2_0 | ||
rsa.FromXmlString(xmlString); | ||
#else | ||
FromXmlStringImpl(rsa, xmlString); | ||
#endif | ||
} | ||
|
||
internal static void FromXmlStringImpl(RSACryptoServiceProvider rsa, string xmlString) | ||
{ | ||
var parameters = new RSAParameters(); | ||
|
||
var xmlDoc = new XmlDocument(); | ||
|
||
xmlDoc.LoadXml(xmlString); | ||
|
||
if (!xmlDoc.DocumentElement.Name.Equals("RSAKeyValue")) | ||
{ | ||
throw new InvalidOperationException("Invalid XML RSA key."); | ||
} | ||
|
||
|
||
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes) | ||
{ | ||
switch (node.Name) | ||
{ | ||
case "Modulus": | ||
parameters.Modulus = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "Exponent": | ||
parameters.Exponent = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "P": | ||
parameters.P = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "Q": | ||
parameters.Q = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "DP": | ||
parameters.DP = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "DQ": | ||
parameters.DQ = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "InverseQ": | ||
parameters.InverseQ = Convert.FromBase64String(node.InnerText); | ||
break; | ||
case "D": | ||
parameters.D = Convert.FromBase64String(node.InnerText); | ||
break; | ||
default: | ||
throw new InvalidOperationException("Unknown node name: " + node.Name); | ||
} | ||
} | ||
|
||
rsa.ImportParameters(parameters); | ||
} | ||
|
||
|
||
|
||
/// <summary> | ||
/// ToXmlString extention method for .net standard, netcoreapp | ||
/// </summary> | ||
/// <param name="rsa"></param> | ||
/// <param name="includePrivateParameters"></param> | ||
/// <returns></returns> | ||
public static void ToXmlString3(this RSA rsa, bool includePrivateParameters = false) | ||
{ | ||
#if !NETSTANDARD2_0 | ||
rsa.ToXmlString(false); | ||
#else | ||
ToXmlStringImpl(rsa, false); | ||
#endif | ||
} | ||
|
||
|
||
internal static string ToXmlStringImpl(this RSA rsa, bool includePrivateParameters = false) | ||
{ | ||
RSAParameters parameters = rsa.ExportParameters(includePrivateParameters); | ||
|
||
if (includePrivateParameters) | ||
{ | ||
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>", | ||
Convert.ToBase64String(parameters.Modulus), | ||
Convert.ToBase64String(parameters.Exponent), | ||
Convert.ToBase64String(parameters.P), | ||
Convert.ToBase64String(parameters.Q), | ||
Convert.ToBase64String(parameters.DP), | ||
Convert.ToBase64String(parameters.DQ), | ||
Convert.ToBase64String(parameters.InverseQ), | ||
Convert.ToBase64String(parameters.D)); | ||
} | ||
|
||
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>", | ||
Convert.ToBase64String(parameters.Modulus), | ||
Convert.ToBase64String(parameters.Exponent)); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// ToXmlString extention method for .net standard, netcoreapp | ||
/// </summary> | ||
/// <param name="rsa"></param> | ||
/// <param name="includePrivateParameters"></param> | ||
/// <returns></returns> | ||
public static string ToXmlString2(this RSA rsa, bool includePrivateParameters = false) | ||
{ | ||
RSAParameters parameters = rsa.ExportParameters(includePrivateParameters); | ||
|
||
if (includePrivateParameters) | ||
{ | ||
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>", | ||
Convert.ToBase64String(parameters.Modulus), | ||
Convert.ToBase64String(parameters.Exponent), | ||
Convert.ToBase64String(parameters.P), | ||
Convert.ToBase64String(parameters.Q), | ||
Convert.ToBase64String(parameters.DP), | ||
Convert.ToBase64String(parameters.DQ), | ||
Convert.ToBase64String(parameters.InverseQ), | ||
Convert.ToBase64String(parameters.D)); | ||
} | ||
|
||
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>", | ||
Convert.ToBase64String(parameters.Modulus), | ||
Convert.ToBase64String(parameters.Exponent)); | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.