I'm try to generate the digest value for a Soap signing, let me explain it
I have the following xml signature (this should be my result)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:srv="...">
<soapenv:Header>
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-A9D96CB86647A0D4FC1673631078676136">
<wsu:Created>2023-02-02T19:11:30.780Z</wsu:Created>
<wsu:Expires>2023-02-02T19:12:00.780Z</wsu:Expires>
</wsu:Timestamp>
<ds:Signature Id="SIG-14C9D524EF6E12B1C61675365090921410" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="soapenv srv" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#TS-A9D96CB86647A0D4FC1673631078676136">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="wsse soapenv srv" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>7UyPvxTBuetBFmJ3rLhKWwUDadF2vsPYMeVsvl5WS5E=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
[...]
</ds:Signature>
</wsse:Security>
</soapenv:Header>
<soapenv:Body></soapenv:Body>
</soapenv:Envelope>
I trying to generate this, using the Timestamp
<ds:DigestValue>7UyPvxTBuetBFmJ3rLhKWwUDadF2vsPYMeVsvl5WS5E=</ds:DigestValue>
I know the following:
I need to sign the timestamp (Element, not content)
I need to use RSA-SHA1 with my RSA private key
Apply SHA256 to the result, and finally convert it to BASE64
<wsu:Timestamp wsu:Id="TS-A9D96CB86647A0D4FC1673631078676136">
<wsu:Created>2023-02-02T19:11:30.780Z</wsu:Created>
<wsu:Expires>2023-02-02T19:12:00.780Z</wsu:Expires>
</wsu:Timestamp>
but when I send it, the server responds the following
Signature verification failed: Core validity=false Signed info validity=false Signed info
message='SignatureValue mismatched.' Ref[0](validity=false message='Digest value mismatch:
calculated: bD55KG25aJxqkvQBe/ZTK1oYEafW3gfyf7okFy40yF0='
uri='#TS-A9D96CB86647A0D4FC1673631078676136' type='null')
Does anyone know how I have to encrypt this content? I read somewhere that I need to apply 'xml-exc-c14n' canonicalization, it's correct? How would the result be after apply the canonicalization?
PD. This is my function to test, I'm using javascript
function encryptRsaSha1(privateKey) {
const message = `<wsu:Timestamp wsu:Id="TS-A9D96CB86647A0D4FC1673631078676136">
<wsu:Created>2023-02-02T19:11:30.780Z</wsu:Created>
<wsu:Expires>2023-02-02T19:12:00.780Z</wsu:Expires>
</wsu:Timestamp>`
const sign = crypto.createSign('RSA-SHA1');
sign.update(message.replace(/\n/g, ''));
sign.end();
const signature = sign.sign(privateKey);
const hash = crypto.createHash('sha256').update(signature).digest('base64');
console.log("Signature: ", hash);
return hash
}
Thanks!
I tried to sign the content in different way, with/without new lines, with/without namespaces, the element, the content, etc.
Related
I am trying to generate encoded docket number from storeId and transactionId. Encoded docket number has to be unique, length should be <=9 and easy to read/copy for users as well.
The maximum length of storeId is 3 and maximum length of transactionId is 5.
How can I improve my code so that my docket number will be unbreakable?
Here is my code:
let myTransKey = 19651;
let myStoreKey = 186;
function generateShortCode(storeId, transactionId) {
//reverse the ids and then add the respective key
var SID = storeId.toString().split("").reverse().join("");
SID = parseInt(SID) + myStoreKey;
var TID = transactionId.toString().split("").reverse().join("");
TID = parseInt(TID) + myTransKey;
var docketNum = `${SID}-${TID}`;
return docketNum;
}
function decodeShortCode(shortCode) {
shortCode = shortCode.split("-");
var storeID = shortCode[0];
var transactionID = shortCode[1];
//subtract the same key and then reverse the ids again
storeID = parseInt(storeID.toString()) - myStoreKey;
storeID = storeID.toString().split("").reverse().join("");
transactionID = parseInt(transactionID.toString()) - myTransKey;
transactionID = transactionID.toString().split("").reverse().join("");
return {
storeId: parseInt(storeID), // store id goes here,
shopDate: new Date(), // the date the customer shopped,
transactionId: parseInt(transactionID) // transaction id goes here
};
}
Is there any better way to do this? I need to encode docket number in a way which will be really hard to decode by any third person.
Every encrypted message can be broken if an attacker tries every possible decryption key (this is called a brute-force attack). With modern computers, this is really easy to do. The way that you are encoding data is very easy to break (within seconds). However, there are encryption methods that take very long to break (like millions of years long).
One of the more popular encryption algorithms is AES. Because it is so popular, there are also many easy-to-use libraries for JavaScript. Here's an example with CryptoJS:
const KEY = "a super secret password";
let myTransKey = 19651;
let myStoreKey = 186;
function generateShortCode(storeId, transactionId) {
const docketNum = `${storeId}-${transactionId}`;
return CryptoJS.AES.encrypt(docketNum, KEY).toString().replace("=", "");
}
function decodeShortCode(shortCode) {
const docketNum = CryptoJS.AES.decrypt(shortCode, KEY).toString(CryptoJS.enc.Utf8);
const parts = docketNum.split("-");
return {
storeId: parseInt(parts[0]), // store id goes here,
shopDate: new Date(), // the date the customer shopped,
transactionId: parseInt(parts[1]) // transaction id goes here
};
}
const s1 = generateShortCode(myStoreKey, myTransKey);
console.log("Short Code: " + s1);
console.log("Decrypted Short Code:", decodeShortCode(s1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js" integrity="sha256-/H4YS+7aYb9kJ5OKhFYPUjSJdrtV6AeyJOtTkw6X72o=" crossorigin="anonymous"></script>
This shortcode is longer than 9 characters, but it very secure and nearly unbreakable. This is really just the tradeoff. If you reduce the length of the shortcode, then you won't be able to have a secure shortcode. Users can still easily copy and paste the code though. If you absolutely need a shorter cipher, then try looking at Skip32.
Be sure to change KEY to a secret key that isn't shared with anyone. Also, be sure not to run this code client-side. If the encryption key is sent to the client, then they could look at the JavaScript code and then be able to decrypt any message.
well this work for me with visual compser in Wordpress
/[[^[]vc[^]]]/ig
I need to interface with third-party organizations. They need to add a digital signature to the data and put it in the request header.
I found that jsrsasign.js could be helpful so I am using that to do the digital signature, but always with the wrong result.
my code:
import { RSAKey, KEYUTIL, KJUR, hex2b64 } from 'jsrsasign'
export function signature (url) {
// 创建RSAKey对象
var rsa = new RSAKey()
let k = '-----BEGIN PRIVATE KEY-----x-----END PRIVATE KEY-----'
// 将密钥转码
rsa = KEYUTIL.getKey(k)
// 创建Signature对象,设置签名编码算法
var sig = new KJUR.crypto.Signature({'alg': 'SHA256withRSA'})
// 初始化
sig.init(rsa)
console.log('***url***', url)
// 传入待加密字符串
sig.updateString(url)
// 生成密文
var sign = hex2b64(sig.sign())
console.log('**sign**', sign)
return sign
}
I'm a jsrsasign maintainer. It shall be work if your code or page is in UTF-8 even though Chinese, Cyrillic or Japanese characters.
I'm trying to verify a webhook coming from Plaid in NodeJS by calculating the Sha256 of the webhook body and I'm following a Python code here where the code is showing :
# Compute the has of the body.
m = hashlib.sha256()
m.update(body.encode())
body_hash = m.hexdigest()
What's the alternative of body.encode() in Javascript before passing it to the Sha256 function please ? Note that the body I'm getting is an object containing the following data :
{ error: null, item_id: '4zAGyokJ1XiWP63QNl1RuLZV76o55nudVXzNG',
new_transactions: 0, webhook_code: 'DEFAULT_UPDATE', webhook_type:
'TRANSACTIONS' }
However I'm trying to get this hash :
b05ef560b59e8d8e427433c5e0f6a11579b5dfe6534257558b896f858007385a
So, if the body is JSON (NOT JSON STRING) then you need to stringify it and put it in the .update function As the m.body takes a string. If you have your body as STRING then just put it in as is.
This is from the Crypto Example here:
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
const stringBody = JSON.stringify(body);
hash.update(stringBody);
console.log(hash.digest('hex'));
Edit:
If the hash is not same then maybe you need to correct the newlines or whitespaces. You need to make both bodies exactly the same. Here In the below example I am using same exact string and encoding using Python AND NodeJS.
import hashlib
body = '{"error":null,"item_id":"4zAGyokJ1XiWP63QNl1RuLZV76o55nudVXzNG","new_transactions":0,"webhook_code":"DEFAULT_UPDATE","webhook_type":"TRANSACTIONS"}'
m = hashlib.sha256()
m.update(body.encode())
body_hash = m.hexdigest()
print(body_hash)
Output:
python3 file.py
26f1120ccaf99a383b7462b233e18994d0c06d4585e3fe9a91a449e97a1c03ba
And Using NodeJS:
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
const body = {
error: null,
item_id: '4zAGyokJ1XiWP63QNl1RuLZV76o55nudVXzNG',
new_transactions: 0,
webhook_code: 'DEFAULT_UPDATE',
webhook_type: 'TRANSACTIONS'
}
const stringBody = JSON.stringify(body);
hash.update(stringBody);
console.log(hash.digest('hex'));
Output:
node file.js
26f1120ccaf99a383b7462b233e18994d0c06d4585e3fe9a91a449e97a1c03ba
I am trying to scrape the data from the below link, in a c# console app:
https://www.eex-transparency.com/homepage/power/germany/production/availability/non-usability
Using the developer tools in chrome I can see that its possible to get a json response, the url to get this is:
https://www.eex-transparency.com/dsp/tem-12?country=de&expires=1454345128&md5=TRhtJei_go4ueLeekBc8yw
the website uses this js file (https://www.eex-transparency.com/assets/js/tpe-website.js) to generate the expires and md5 hash key. I think I've figured out that the expires value is a unix datetime. I have never used javascript before so finding it hard to figure out how they construct the md5.
The Javascript that generates these code is:
generateCryptedParams=function(url,clientIP)
{
var cryptedParams,md5,md5Encoded,md5WithoutSpeciaChars,parser,timePoint,urlPath;
return timePoint=moment().tz("Europe/Berlin").add(1,"minute").unix(),
parser=document.createElement("a"),
parser.href=url,
urlPath=parser.pathname,
"/"!==urlPath[0]&&(urlPath="/"+urlPath),
md5=CryptoJS.MD5(urlPath+timePoint+clientIP+" zYeHzBomGdgV"),
md5Encoded=md5.toString(CryptoJS.enc.Base64),
md5WithoutSpeciaChars=replaceSpecialChars(md5Encoded),
cryptedParams={"expires":timePoint,"md5":md5WithoutSpeciaChars}
}
replaceSpecialChars=function(str)
{
var key,specialChars,value;
specialChars={"=":"","\\+":"-","/":"_","%":"_"};
for(key in specialChars)
value=specialChars[key],
str=str.replace(new RegExp(key,"g"),value);
return str
}
As i said I think I'm comfortable with the timepoint part but the md5 is confusing me. Below is my C# code to replicate their but when I pass the md5 hash their site returns a 403 Forbidden error.
public Tuple<string, Int32> GenerateCrypto(string url, string ipAddress)
{
string cetId = "Central European Standard Time";
TimeZoneInfo cetZone = TimeZoneInfo.FindSystemTimeZoneById(cetId);
var CETDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, cetZone);
//Int32 unixTimestamp = (Int32)(CETDateTime.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
Int32 unixTimestamp = (Int32)(DateTime.UtcNow.AddMinutes(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
url = url.Split('/')[3];
var md5 = CipherUtility.GenerateMd5(url + unixTimestamp + ipAddress + " zYeHzBomGdgV");
var md5Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(md5));
var md5withoutSpecialCharts = replaceSpecialChars(md5Encoded);
md5withoutSpecialCharts = md5withoutSpecialCharts.Substring(0, 22);
return new Tuple<string, Int32>(md5withoutSpecialCharts, unixTimestamp);
}
The solution was that I needed to concatenate a const string to all the elements before hashing it.
I am using Xpath Extractor to find out a node value from a XML response but Jmeter is throwing an error every time I execute with the following error:
jmeter.extractor.XPathExtractor: TransformerException while processing
((//*[local-name() = 'RequestID'])[2]/text()) -1
The xpath expression used in Jmeter: (//*[local-name() = 'RequestID'])[2]/text()
I checked my xpath expression online and its valid and returning the expected value. Not sure what is the problem with jmeter.
Here is the xml:
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<urn1:ServiceControl xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">
<urn1:EmergencyRequestIndicator>true</urn1:EmergencyRequestIndicator>
<urn1:VersionID>1.0</urn1:VersionID>
<urn1:LanguageCode type="Advisor">en-US</urn1:LanguageCode>
<urn1:LanguageCode type="Subscriber">en-US</urn1:LanguageCode>
<urn1:ApplicationID>GAA</urn1:ApplicationID>
<urn1:LogicalID>W2DZD0Y06</urn1:LogicalID>
<urn1:ComponentID>GAA-ocsComponent</urn1:ComponentID>
<urn1:ReferenceID>CorrelationId</urn1:ReferenceID>
<urn1:SentTimeStamp>2010-04-23T14:27:10Z</urn1:SentTimeStamp>
<urn1:MessageType>ocsMessageType</urn1:MessageType>
<urn1:ChannelID>GAA</urn1:ChannelID>
<urn1:TaskID>ocsTask</urn1:TaskID>
<urn1:Environment>4.0</urn1:Environment>
<urn1:BODID>GAA-CorrelationId</urn1:BODID>
<urn1:Asynchronous>
<urn1:TimeToLive xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">10</urn1:TimeToLive>
<urn1:PassThroughData xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">
<urn1:Key xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">1</urn1:Key>
<urn1:Value xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">10</urn1:Value>
</urn1:PassThroughData>
<urn1:ExpectedResponseTime xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">30</urn1:ExpectedResponseTime>
<urn1:RequestID xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">100</urn1:RequestID>
<urn1:RetryStrategy xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">
<urn1:Name xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">RetryName</urn1:Name>
<urn1:LongTermRetryIndicator xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">false</urn1:LongTermRetryIndicator>
<urn1:ResponseRequiredOnErrorPoolMoveIndicator xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">true</urn1:ResponseRequiredOnErrorPoolMoveIndicator>
</urn1:RetryStrategy>
<urn1:ReplyRequiredIndicator xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">true</urn1:ReplyRequiredIndicator>
<urn1:ReplyToMessageID xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">1000</urn1:ReplyToMessageID>
<urn1:CallbackURI xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">urn1:www:com</urn1:CallbackURI>
<urn1:FaultURI xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">urn1:www:com</urn1:FaultURI>
<urn1:ProcessingModes xmlns:urn1="urn:com:sample:global:common:schema:ServiceControl:2">ProcessingMode</urn1:ProcessingModes>
</urn1:Asynchronous>
<urn1:Synchronous/>
</urn1:ServiceControl>
</S:Header>
<S:Body>
<ns2:ServiceRequestReference xmlns="urn:com:sample:ocs:common:schema:AutoTask:11" xmlns:ns10="urn:com:sample:global:common:schema:CallContext:2" xmlns:ns11="urn:com:sample:ocs:common:schema:ServiceFault:11" xmlns:ns12="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ns13="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns14="http://www.w3.org/2000/09/xmldsig#" xmlns:ns15="urn:com:sample:global:common:schema:ServiceControl:2" xmlns:ns2="urn:com:sample:ocs:common:schema:CommonTypes:11" xmlns:ns3="urn:com:sample:ocs:common:schema:AutoInformation:11" xmlns:ns4="urn:com:sample:ocs:common:schema:UnitConfiguration:11" xmlns:ns5="urn:com:sample:ocs:common:schema:SubscriberRequest:11" xmlns:ns6="urn:com:sample:ocs:common:schema:ElectricAuto:11" xmlns:ns7="urn:com:sample:ocs:common:schema:EmergencyRequest:11" xmlns:ns8="urn:com:sample:ocs:common:schema:AutoRequest:11" xmlns:ns9="urn:com:sample:ocs:common:schema:AutoConnection:11">
<ns2:RequestID>2648331</ns2:RequestID>
<ns2:isProcessingAnotherRequest>false</ns2:isProcessingAnotherRequest>
<ns2:estimatedProcessingTime>0</ns2:estimatedProcessingTime>
</ns2:ServiceRequestReference>
</S:Body>
</S:Envelope>
You can subtract 1 from variable using i.e. Beanshell Post Processor
Assuming that you use RequestID as a reference name in XPath Extractor and following XPath is being used to get RequestID
(//*[local-name() = 'RequestID'])[2]/text()
or
//ns2:RequestID/text()
Next Beanshell code will allow you to manipulate the variable
int requestId = Integer.parseInt(vars.get("RequestID"));
requestId = requestId--;
vars.put("RequestID", String.valueOf(requestId));