I can get a public key from a certificate file,and use code below to encrypt a message with sm2engine.
public static String encrypt(String data, PublicKey publicKey)
{
ECPublicKeyParameters localECPublicKeyParameters = null;
if (publicKey instanceof BCECPublicKey)
{
BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(
localECParameterSpec.getCurve(), localECParameterSpec.getG(),
localECParameterSpec.getN());
localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(),
localECDomainParameters);
}
SM2Engine localSM2Engine = new SM2Engine();
localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters,
new SecureRandom()));
byte[] arrayOfByte2;
try
{
arrayOfByte2 = localSM2Engine.processBlock(data.getBytes(), 0, data.getBytes().length);
return new String(Base64.encode(arrayOfByte2));
}
catch (InvalidCipherTextException e)
{
e.printStackTrace();
return null;
}
But it is not enveloped,I do not know how to add an envelop on it,but I know how to add envelop without sm2egine:
public static String encryptMessage(String message, X509Certificate cert) throws Exception {
CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert));
OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BouncyCastleProvider.PROVIDER_NAME).build();
CMSTypedData content = new CMSProcessableByteArray(message.getBytes("UTF-8"));
CMSEnvelopedData data = gen.generate(content, encryptor);
String encryptedMessage = new String(Base64.encode(data.getEncoded()));
return encryptedMessage;
}
but now I must use the special algorithm called sm4 as the symmetric algorithm to encrypt the content first,not aes.And then use sm2 to encypt the key of sm4,all as it defined in pkcs7.so how to join these two code fragment?
All special algorithms seem can be implemented by BouncyCastle method,but there is no sm4 in CMSAlgorithm class,but I found a GMObjectIndenrifier.sms4_cbc,and pass it as a parameter,but got a exception:
no such algorithm.
More info:after I parse the certificate from a file, and call certificate.getSigAlgName(),its name is SM3WITHSM2
Related
I am facing an issue with the following code
public static void main(String[] args) throws NoSuchAlgorithmException {
String key = "test";
SecretKeySpec secretKeySpec = new
SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
Mac mac = Mac.getInstance("HmacSHA512");
try {
if (null != mac) {
mac.init(secretKeySpec);
}
} catch (InvalidKeyException e) {
}
IntStream.range(1, 12).parallel().forEach(d->{
final byte[] bytes = "somestring".getBytes(StandardCharsets.UTF_8);
final byte[] doFinal= mac.doFinal(bytes);
String digest = Base64.getEncoder().encodeToString(doFinal);
LOGGER.info("digest -- {} ", digest);
});
}
Even the string is the same but digests generated using a mac.doFinal is different. This is just a showcase of the issue. I have used the same code in my spring reactive application where mac is a bean and digest generated every time when user make a request which is a concurrent request where also i have seen these weird behavior.
I have to create an application which has XML data and creates Hash for signing and send the hash to an API to get the raw signature for XML and append signature for XML in Java How can I achieve this.
The same thing can be done in .Net by overriding SignedXml class like this
public class CustomSignedXml: SignedXml
{
public CustomSignedXml(XmlDocument xmlDoc) : base(xmlDoc)
{
}
public void ComputeSignature()
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
MethodInfo methodInfo = typeof(SignedXml).GetMethod("BuildDigestedReferences", BindingFlags.Instance | BindingFlags.NonPublic);
methodInfo.Invoke(this, null);
SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription;
if (signatureDescription == null)
throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");
HashAlgorithm hashAlg = signatureDescription.CreateDigest();
if (hashAlg == null)
throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
MethodInfo methodInfo2 = typeof(SignedXml).GetMethod("GetC14NDigest", BindingFlags.Instance | BindingFlags.NonPublic);
byte[] hashvalue = (byte[])methodInfo2.Invoke(this, new object[] { hashAlg });
var signature = GetSignatureFromServer(hashvalue);
m_signature.SignatureValue = signature;
}
}
And use CustomSignedXml class to sign using following meathod
public string GetSignedXml(string xmlDoc, X509Certificate2 PublicCertificate)
{
try
{
XmlDocument xmlDocumentToSign = new XmlDocument();
xmlDocumentToSign.LoadXml(xmlDoc);
CustomSignedXml signedXml = new CustomSignedXml(xmlDocumentToSign);
Reference reference = new Reference();
reference.Uri = "";
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signedXml.AddReference(reference);
signedXml.ComputeSignature();
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(GetKeyInfoData(PublicCertificate));
signedXml.KeyInfo = keyInfo;
var xmlDigitalSignature = signedXml.GetXml();
xmlDocumentToSign.DocumentElement.AppendChild(xmlDocumentToSign.ImportNode(xmlDigitalSignature, true));
return xmlDocumentToSign.OuterXml;
}
catch (Exception)
{
throw;
}
}
How can I do the same in JAVA
How to sign a post(any document or text) in browser using smart card.
What I have investigated so far:
ActiveX - IE only
Silverlight - no access to certificates at all and as a plugin faces the same limitations as Java
Browser specific extensions; For example Firefox up until version 33 used to have window.crypto.signText but not anymore
local applications installed on the client - not easy to install, support, develop and update for several OS and their different versions.
Web Cryptography - "only basic cryptographic functions", no certificates support
I ran out of ideas.
All suggestions are welcome and appreciated.
i tried a java applet the code is here below. main class: Smartcard applet.java public class SmartCardSignerApplet extends Applet {
private static final String FILE_NAME_FIELD_PARAM = "fileNameField";
private static final String CERT_CHAIN_FIELD_PARAM = "certificationChainField";
private static final String SIGNATURE_FIELD_PARAM = "signatureField";
private static final String SIGN_BUTTON_CAPTION_PARAM = "signButtonCaption";
private static final String PKCS11_KEYSTORE_TYPE = "PKCS11";
private static final String X509_CERTIFICATE_TYPE = "X.509";
private static final String CERTIFICATION_CHAIN_ENCODING = "PkiPath";
private static final String DIGITAL_SIGNATURE_ALGORITHM_NAME = "SHA1withRSA";
private static final String SUN_PKCS11_PROVIDER_CLASS = "sun.security.pkcs11.SunPKCS11";
private Button mSignButton; //initialises applet public void init() {
String signButtonCaption = this.getParameter(SIGN_BUTTON_CAPTION_PARAM);
mSignButton = new Button(signButtonCaption);
mSignButton.setLocation(0, 0);
Dimension appletSize = this.getSize();
mSignButton.setSize(appletSize);
mSignButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
signSelectedFile();
}
});
this.setLayout(null);
this.add(mSignButton);
} \\ signing the file private void signSelectedFile() {
try {
// Get the file name to be signed from the form in the HTML document
JSObject browserWindow = JSObject.getWindow(this);
JSObject mainForm = (JSObject) browserWindow.eval("document.forms[0]");
String fileNameFieldName = this.getParameter(FILE_NAME_FIELD_PARAM);
JSObject fileNameField = (JSObject) mainForm.getMember(fileNameFieldName);
String fileName = (String) fileNameField.getMember("value");
// Perform the actual file signing
CertificationChainAndSignatureBase64 signingResult = signFile(fileName);
if (signingResult != null) {
// Document signed. Fill the certificate and signature fields
String certChainFieldName = this.getParameter(CERT_CHAIN_FIELD_PARAM);
JSObject certChainField = (JSObject) mainForm.getMember(certChainFieldName);
certChainField.setMember("value", signingResult.mCertificationChain);
String signatureFieldName = this.getParameter(SIGNATURE_FIELD_PARAM);
JSObject signatureField = (JSObject) mainForm.getMember(signatureFieldName);
signatureField.setMember("value", signingResult.mSignature);
} else {
// User canceled signing
}
}
catch (DocumentSignException dse) {
// Document signing failed. Display error message
String errorMessage = dse.getMessage();
JOptionPane.showMessageDialog(this, errorMessage);
}
catch (SecurityException se) {
se.printStackTrace();
JOptionPane.showMessageDialog(this,
"Unable to access the local file system.\n" +
"This applet should be started with full security permissions.\n" +
"Please accept to trust this applet when the Java Plug-In ask you.");
}
catch (JSException jse) {
jse.printStackTrace();
JOptionPane.showMessageDialog(this,
"Unable to access some of the fields of the\n" +
"HTML form. Please check the applet parameters.");
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "Unexpected error: " + e.getMessage());
}
}
private CertificationChainAndSignatureBase64 signFile(String aFileName)
throws DocumentSignException {
// Load the file for signing
byte[] documentToSign = null;
try {
documentToSign = readFileInByteArray(aFileName);
} catch (IOException ioex) {
String errorMessage = "Can not read the file for signing " + aFileName + ".";
throw new DocumentSignException(errorMessage, ioex);
}
// Show a dialog for choosing PKCS#11 implementation library and smart card PIN
PKCS11LibraryFileAndPINCodeDialog pkcs11Dialog =
new PKCS11LibraryFileAndPINCodeDialog();
boolean dialogConfirmed;
try {
dialogConfirmed = pkcs11Dialog.run();
} finally {
pkcs11Dialog.dispose();
}
if (dialogConfirmed) {
String oldButtonLabel = mSignButton.getLabel();
mSignButton.setLabel("Working...");
mSignButton.setEnabled(false);
try {
String pkcs11LibraryFileName = pkcs11Dialog.getLibraryFileName();
String pinCode = pkcs11Dialog.getSmartCardPINCode();
// Do the actual signing of the document with the smart card
CertificationChainAndSignatureBase64 signingResult =
signDocument(documentToSign, pkcs11LibraryFileName, pinCode);
return signingResult;
} finally {
mSignButton.setLabel(oldButtonLabel);
mSignButton.setEnabled(true);
}
}
else {
return null;
}
}
private CertificationChainAndSignatureBase64 signDocument(
byte[] aDocumentToSign, String aPkcs11LibraryFileName, String aPinCode)
throws DocumentSignException {
if (aPkcs11LibraryFileName.length() == 0) {
String errorMessage = "It is mandatory to choose a PCKS#11 native " +
"implementation library for for smart card (.dll or .so file)!";
throw new DocumentSignException(errorMessage);
}
// Load the keystore from the smart card using the specified PIN code
KeyStore userKeyStore = null;
try {
userKeyStore = loadKeyStoreFromSmartCard(aPkcs11LibraryFileName, aPinCode);
} catch (Exception ex) {
String errorMessage = "Can not read the keystore from the smart card.\n" +
"Possible reasons:\n" +
" - The smart card reader in not connected.\n" +
" - The smart card is not inserted.\n" +
" - The PKCS#11 implementation library is invalid.\n" +
" - The PIN for the smart card is incorrect.\n" +
"Problem details: " + ex.getMessage();
throw new DocumentSignException(errorMessage, ex);
}
// Get the private key and its certification chain from the keystore
PrivateKeyAndCertChain privateKeyAndCertChain = null;
try {
privateKeyAndCertChain =
getPrivateKeyAndCertChain(userKeyStore);
} catch (GeneralSecurityException gsex) {
String errorMessage = "Can not extract the private key and " +
"certificate from the smart card. Reason: " + gsex.getMessage();
throw new DocumentSignException(errorMessage, gsex);
}
// Check if the private key is available
PrivateKey privateKey = privateKeyAndCertChain.mPrivateKey;
if (privateKey == null) {
String errorMessage = "Can not find the private key on the smart card.";
throw new DocumentSignException(errorMessage);
}
// Check if X.509 certification chain is available
Certificate[] certChain = privateKeyAndCertChain.mCertificationChain;
if (certChain == null) {
String errorMessage = "Can not find the certificate on the smart card.";
throw new DocumentSignException(errorMessage);
}
// Create the result object
CertificationChainAndSignatureBase64 signingResult =
new CertificationChainAndSignatureBase64();
// Save X.509 certification chain in the result encoded in Base64
try {
signingResult.mCertificationChain = encodeX509CertChainToBase64(certChain);
}
catch (CertificateException cee) {
String errorMessage = "Invalid certificate on the smart card.";
throw new DocumentSignException(errorMessage);
}
// Calculate the digital signature of the file,
// encode it in Base64 and save it in the result
try {
byte[] digitalSignature = signDocument(aDocumentToSign, privateKey);
signingResult.mSignature = Base64Utils.base64Encode(digitalSignature);
} catch (GeneralSecurityException gsex) {
String errorMessage = "File signing failed.\n" +
"Problem details: " + gsex.getMessage();
throw new DocumentSignException(errorMessage, gsex);
}
return signingResult;
}
/**
* Loads the keystore from the smart card using its PKCS#11 implementation
* library and the Sun PKCS#11 security provider. The PIN code for accessing
* the smart card is required.
*/
private KeyStore loadKeyStoreFromSmartCard(String aPKCS11LibraryFileName,
String aSmartCardPIN)
throws GeneralSecurityException, IOException {
// First configure the Sun PKCS#11 provider. It requires a stream (or file)
// containing the configuration parameters - "name" and "library".
String pkcs11ConfigSettings =
"name = SmartCard\n" + "library = " + aPKCS11LibraryFileName;
byte[] pkcs11ConfigBytes = pkcs11ConfigSettings.getBytes();
ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11ConfigBytes);
// Instantiate the provider dynamically with Java reflection
try {
Class sunPkcs11Class = Class.forName(SUN_PKCS11_PROVIDER_CLASS);
Constructor pkcs11Constr = sunPkcs11Class.getConstructor(
java.io.InputStream.class);
Provider pkcs11Provider = (Provider) pkcs11Constr.newInstance(confStream);
Security.addProvider(pkcs11Provider);
} catch (Exception e) {
throw new KeyStoreException("Can initialize Sun PKCS#11 security " +
"provider. Reason: " + e.getCause().getMessage());
}
// Read the keystore form the smart card
char[] pin = aSmartCardPIN.toCharArray();
KeyStore keyStore = KeyStore.getInstance(PKCS11_KEYSTORE_TYPE);
keyStore.load(null, pin);
return keyStore;
}
/**
* #return private key and certification chain corresponding to it, extracted from
* given keystore. The keystore is considered to have only one entry that contains
* both certification chain and its corresponding private key. If the keystore has
* no entries, an exception is thrown.
*/
private PrivateKeyAndCertChain getPrivateKeyAndCertChain(
KeyStore aKeyStore)
throws GeneralSecurityException {
Enumeration aliasesEnum = aKeyStore.aliases();
if (aliasesEnum.hasMoreElements()) {
String alias = (String)aliasesEnum.nextElement();
Certificate[] certificationChain = aKeyStore.getCertificateChain(alias);
PrivateKey privateKey = (PrivateKey) aKeyStore.getKey(alias, null);
PrivateKeyAndCertChain result = new PrivateKeyAndCertChain();
result.mPrivateKey = privateKey;
result.mCertificationChain = certificationChain;
return result;
} else {
throw new KeyStoreException("The keystore is empty!");
}
}
/**
* #return Base64-encoded ASN.1 DER representation of given X.509 certification
* chain.
*/
private String encodeX509CertChainToBase64(Certificate[] aCertificationChain)
throws CertificateException {
List certList = Arrays.asList(aCertificationChain);
CertificateFactory certFactory =
CertificateFactory.getInstance(X509_CERTIFICATE_TYPE);
CertPath certPath = certFactory.generateCertPath(certList);
byte[] certPathEncoded = certPath.getEncoded(CERTIFICATION_CHAIN_ENCODING);
String base64encodedCertChain = Base64Utils.base64Encode(certPathEncoded);
return base64encodedCertChain;
}
/**
* Reads the specified file into a byte array.
*/
private byte[] readFileInByteArray(String aFileName)
throws IOException {
File file = new File(aFileName);
FileInputStream fileStream = new FileInputStream(file);
try {
int fileSize = (int) file.length();
byte[] data = new byte[fileSize];
int bytesRead = 0;
while (bytesRead < fileSize) {
bytesRead += fileStream.read(data, bytesRead, fileSize-bytesRead);
}
return data;
}
finally {
fileStream.close();
}
}
/**
* Signs given document with a given private key.
*/
private byte[] signDocument(byte[] aDocument, PrivateKey aPrivateKey)
throws GeneralSecurityException {
Signature signatureAlgorithm =
Signature.getInstance(DIGITAL_SIGNATURE_ALGORITHM_NAME);
signatureAlgorithm.initSign(aPrivateKey);
signatureAlgorithm.update(aDocument);
byte[] digitalSignature = signatureAlgorithm.sign();
return digitalSignature;
}
/**
* Data structure that holds a pair of private key and
* certification chain corresponding to this private key.
*/
static class PrivateKeyAndCertChain {
public PrivateKey mPrivateKey;
public Certificate[] mCertificationChain;
}
/**
* Data structure that holds a pair of Base64-encoded
* certification chain and digital signature.
*/
static class CertificationChainAndSignatureBase64 {
public String mCertificationChain = null;
public String mSignature = null;
}
/**
* Exception class used for document signing errors.
*/
static class DocumentSignException extends Exception {
public DocumentSignException(String aMessage) {
super(aMessage);
}
public DocumentSignException(String aMessage, Throwable aCause) {
super(aMessage, aCause);
}
}
} While i run the applet i get a message for ckr operations not found . any help?
I have following code written in Java
Mac mac = Mac.getInstance("HmacSHA1");
String secretKey ="sKey";
String content ="Hello";
byte[] secretKeyBArr = secretKey.getBytes();
byte[] contentBArr = content.getBytes();
SecretKeySpec secret_key = new SecretKeySpec(secretKeyBArr,"HmacSHA1");
byte[] secretKeySpecArr = secret_key.getEncoded();
mac.init(secret_key);
byte[] final = mac.doFinal(contentBArr);
I want to make same example in C#. So, I wrote following code
HMACSHA1 hmacsha1 = new HMACSHA1();
string secretKey = "sKey";
string content = "Hello";
byte[] secretKeyBArr = Encoding.UTF8.GetBytes(secretKey);
byte[] contentBArr = Encoding.UTF8.GetBytes(content);
hmacsha1.Key = secretKeyBArr;
byte[] final = hmacsha1.ComputeHash(contentBArr);
Final results are not equal. secretKeyBArr and contentBArr are byte array and their values are same in both example. What is unknown is SecretKeySpec passed to mac.init(). So, what is equivalent same class in C#?
The results are identical, but Java uses signed bytes while C# uses unsigned bytes by default.
Furthermore, SecretKeySpec itself normally does not change the underlying data. You need to e.g. put a DES key specification in a SecretKeyFactory to make sure that the parity bits are set correctly (in the resulting SecretKey). So there is no need for an equivalent as the class itself does very little except wrapping the data.
I'm implementing a credit card payment method form a provider (cardinity) that doesn't provide a .net implementation. I'm looking for similar stuff and end-up writing my own as my google skills seem to be ....
What I need is the base64 string of javax.crypto.mac
I am supporting the following methods:
enum EncryptionMethods
{
None=0,
HMACSHA1,
HMACSHA256,
HMACSHA384,
HMACSHA512,
HMACMD5
}
I have implemented the code you have above, the SecretKeySpec and the Mac the following way (you need System.Security.Cryptography.ProtectedData):
internal class Protected
{
private Byte[] salt = Guid.NewGuid().ToByteArray();
protected byte[] Protect(byte[] data)
{
try
{
return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
return null;
}
}
protected byte[] Unprotect(byte[] data)
{
try
{
return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
return null;
}
}
}
internal class SecretKeySpec:Protected,IDisposable
{
readonly EncryptionMethods _method;
private byte[] _secretKey;
public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
{
_secretKey = Protect(secretKey);
_method = encryptionMethod;
}
public EncryptionMethods Method => _method;
public byte[] SecretKey => Unprotect( _secretKey);
public void Dispose()
{
if (_secretKey == null)
return;
//overwrite array memory
for (int i = 0; i < _secretKey.Length; i++)
{
_secretKey[i] = 0;
}
//set-null
_secretKey = null;
}
~SecretKeySpec()
{
Dispose();
}
}
internal class Mac : Protected,IDisposable
{
byte[] rawHmac;
HMAC mac;
public Mac(SecretKeySpec key, string data)
{
switch (key.Method)
{
case EncryptionMethods.HMACMD5:
mac = new HMACMD5(key.SecretKey);
break;
case EncryptionMethods.HMACSHA512:
mac = new HMACSHA512(key.SecretKey);
break;
case EncryptionMethods.HMACSHA384:
mac = new HMACSHA384(key.SecretKey);
break;
case EncryptionMethods.HMACSHA256:
mac = new HMACSHA256(key.SecretKey);
break;
case EncryptionMethods.HMACSHA1:
mac = new HMACSHA1(key.SecretKey);
break;
default:
throw new NotSupportedException("not supported HMAC");
}
rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));
}
public string AsBase64()
{
return System.Convert.ToBase64String(Unprotect(rawHmac));
}
public void Dispose()
{
if (rawHmac != null)
{
//overwrite memory address
for (int i = 0; i < rawHmac.Length; i++)
{
rawHmac[i] = 0;
}
//release memory now
rawHmac = null;
}
mac?.Dispose();
mac = null;
}
~Mac()
{
Dispose();
}
}
I have implemented this in an OAuthSigner class the following way:
public override string ComputeSignature(string plainTextToEncode, string consumerSecret)
{
var key = PercentEncode(consumerSecret) + "&";
try
{
using (var secretKey = new SecretKeySpec(key.GetBytes(), EncryptionMethods.HMACSHA1))
using (Mac mac = new Mac(secretKey, plainTextToEncode))
{
return mac.AsBase64();
}
}
finally
{
key = null;//free memory, remove sensitive data
}
}
Then, it's not what you ask for but I need a helper method as I am sending my text to a web service that goes like this and I include it as some might copy the code:
public static String PercentEncode(string textToEncode)
{
return string.IsNullOrEmpty(textToEncode)
?""
: UrlEncoder.Default.Encode(Cardinity.ENCODING.GetString(Cardinity.ENCODING.GetBytes(textToEncode)))
.Replace("+", "%20").Replace("*", "%2A")
.Replace("%7E", "~");
}
The class UrlEncoder comes from System.Text.Encodings.Web, you may have to add a reference.
The class named Cardinity implements a "short-cut" to the Encoding that I use for Cardinity
public abstract class Cardinity
{
...
public static String API_BASE = "https://api.cardinity.com";
public static String API_VERSION = "v1";
public static String VERSION = "0.1";
public static String ENCODING_CHARSET = "UTF-8";
public static Encoding ENCODING => Encoding.UTF8;
}
as Java uses string.GetBytes a lot, I have added an extension method for this that I call above in the key.GetBytes(), here is the extension code:
public static byte[] GetBytes(this string sender)=>
Cardinity.ENCODING.GetBytes(sender);
My test method, I have copied the values from Cardinity API passes without any issues.
private OAuthSigner signer;
public HmacOAuthSigner_Test()
{
signer = new HmacOAuthSigner();
}
[TestMethod]
public void Test_HmacOAuthSigner_ComputeSignature_DefaultText()
{
var expects = "PxkffxyQh6jsDNcgJ23GpAxs2y8=";
var test_data = "justsomerandommessage";
var secretkey = "yvp0leodf231ihv9u29uuq6w8o4cat9qz2nkvs55oeu833s621";
var actual = signer.ComputeSignature(test_data, secretkey);
Assert.AreEqual(expects, actual, $"Expecting {test_data} to return {expects} received {actual}");
}
The whole implementation of the HmacOAuthSigner is here, it implements an abstract class with the PercentEncode method in it.
public class HmacOAuthSigner : OAuthSigner
{
public override string ComputeSignature(string signatureBaseString, string consumerSecret)
{
var key = PercentEncode(consumerSecret) + "&";
var secretKey = new SecretKeySpec(key.GetBytes(), EncryptionMethods.HMACSHA1);
using (Mac mac = new Mac(secretKey, signatureBaseString))
{
return mac.AsBase64();
}
}
public override string GetSignatureMethod()
{
return "HMAC-SHA1";
}
}
and the abstract class that I use as a contract for all the implementations:
public abstract class OAuthSigner
{
/// <summary>
/// Signature method used
/// </summary>
/// <returns>a string that tells the implementation method</returns>
public abstract string GetSignatureMethod();
/// <summary>
/// computes the signature that is used with the encryption based on the keys provided by cardinity
/// </summary>
/// <param name="signatureBaseString">The secret string that services as a base</param>
/// <param name="consumerSecret">The consumer key as specified in the API settings</param>
/// <returns>signature string computed by the provided parameters using the signature method</returns>
public abstract string ComputeSignature(String signatureBaseString, String consumerSecret);
/// <summary>
/// Encode a string into a format expected by Cardinity
/// </summary>
/// <param name="textToEncode">The text that is to be encoded</param>
/// <returns>web encoded string ready for using to send to Cardinity</returns>
public static String PercentEncode(string textToEncode)
{
return string.IsNullOrEmpty(textToEncode)
?""
: UrlEncoder.Default.Encode(Cardinity.ENCODING.GetString(Cardinity.ENCODING.GetBytes(textToEncode)))
.Replace("+", "%20").Replace("*", "%2A")
.Replace("%7E", "~");
}
}
I am running a java string encryption/decryption class that i got from the internet! Here is the class with little modification :
public class EncrypterDecrypter
{
Cipher ecipher;
Cipher dcipher;
EncrypterDecrypter(SecretKey key)
{
try {
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (javax.crypto.NoSuchPaddingException e) {
} catch (java.security.NoSuchAlgorithmException e) {
} catch (java.security.InvalidKeyException e) {
}
}
}
public class EncryptionTester
{
public static void main(String[] args)
{
try
{
//Generate a temporary key.
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
//Create Encrypter/Decrypter class
EncrypterDecrypter crypto = new EncrypterDecrypter(key);
//More lines of code to use crypto object
}
catch (Exception e)
{
}
}
}
My problem is that each time i create an new instance of EncrypterDecrypter class i get differents encrypted string yet the string to encrypt is still the same! My mind tells me that the problem would be the SecretKey object which keeps changing each time there is a new instance created, i would like to know how i can make the SecretKey object the same for all instances of Encrypter/Decrypter Class if that be the cause of the problem!
If you used the javax.crypto package, then the encrypt and decryp methods look okay.
Try to generate your key like that:
final SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
final SecretKey key = skf.generateSecret(new DESKeySpec(new byte [] {/*The key*/}));
instance.EncrypterDecrypter(key); //Initialization of your Cipher objects
String encrypted = instance.encrypt("This is a test");
System.out.println(instance.decrypt(encrypted)); //"This is a test"
You should do something in the catches.
Generate SecretKey from a byte array..
byte raw[] = new byte[]{0x001,0x002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002};
SecretKeySpec spec = new SecretKeySpec(raw, "DES");