Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jsrsasign vulnerable to the Marvin Attack #598

Closed
tomato42 opened this issue Nov 21, 2023 · 3 comments
Closed

jsrsasign vulnerable to the Marvin Attack #598

tomato42 opened this issue Nov 21, 2023 · 3 comments

Comments

@tomato42
Copy link

tomato42 commented Nov 21, 2023

(Since I haven't found a security policy that would ask for filing security issues over email, I'm making a regular bug report)

I've tested jsrsasign 10.8.6 on nodejs 21.1.0 and I have found it vulnerable to the Marvin Attack.

Looking at the results, both the bit size of the raw RSA decryption is leaking (so all padding modes will be vulnerable, both PKCS#1 v1.5 and OAEP), and in case of PKCS#1 v1.5 the size of the decrypted message is leaking. As such, it provides timing oracles useful in mounting a timing variant of the Bleichenbacher attack.

I've collected 10000 measurements per sample on an isolated core of an AMD Ryzen 5 5600X.
The test returned statistically significant results even with 100 measurements per sample, I've executed with with 10000 to look for side channels other then the bit size of the raw RSA operation. That means that the returned p-values are 0, as they are smaller in reality than a double precision floating point numbers can represent.
For 100k measurements the summary looks as follows:

Sign test mean p-value: 0.08346, median p-value: 6.623e-14, min p-value: 0.0
Friedman test (chisquare approximation) for all samples
p-value: 0.0
Worst pair: 2(no_padding_48), 11(zero_byte_in_padding_48_4)
Mean of differences: 2.67060e-05s, 95% CI: 2.39585e-05s, 2.993167e-05s (±2.987e-06s)
Median of differences: 2.61110e-05s, 95% CI: 2.55910e-05s, 2.649050e-05s (±4.498e-07s)
Trimmed mean (5%) of differences: 2.59561e-05s, 95% CI: 2.51313e-05s, 2.690085e-05s (±8.848e-07s)
Trimmed mean (25%) of differences: 2.59850e-05s, 95% CI: 2.56003e-05s, 2.642811e-05s (±4.139e-07s)
Trimmed mean (45%) of differences: 2.60091e-05s, 95% CI: 2.56006e-05s, 2.643911e-05s (±4.193e-07s)
Trimean of differences: 2.60815e-05s, 95% CI: 2.56166e-05s, 2.649325e-05s (±4.383e-07s)

and the confidence interval graph for the individual probes:
conf_interval_plot_trim_mean_25
Legend to the graph:

ID,Name
0,header_only
1,no_header_with_payload_48
2,no_padding_48
3,no_structure
4,signature_padding_8
5,valid_0
6,valid_48
7,valid_192
8,valid_246
9,valid_repeated_byte_payload_246_1
10,valid_repeated_byte_payload_246_255
11,zero_byte_in_padding_48_4

Explanation for the ciphertexts is in the step2.py file.

Side note: the valid_246 probe is actually invalid, it has padding string of 7 bytes, which is less than the mandatory 8.

The reproducer I used for the test:

var program = require('commander');
var rs = require('jsrsasign');
var rsu = require('jsrsasign-util');
var path = require('path');
var fs = require('fs');

program
  .version('1.0.0 (2016-Nov-05)')
  .usage('[options] <encrypted data file> <output time file or "-"> <PEM RSA private key file> [RSA|RSAOEAP*>]')
  .description('encrypt data')
  .parse(process.argv);

if (program.args.length < 3)
  throw "wrong number of arguments";

var keyObj, inHex, encHex;
var algName = "RSA";
var keyStr = "";
var inFileOrHex = program.args[0];
var outFile = program.args[1];
var keyFileOrStr = program.args[2];
if (program.args.length > 3) algName = program.args[3];

try {
  keyStr = rsu.readFile(keyFileOrStr);
} catch(ex) {
  keyStr = keyFileOrStr;
}

try {
  keyObj = rs.KEYUTIL.getKey(keyStr);
} catch(ex) {};


const fileDescriptor = fs.openSync(inFileOrHex, 'r');

const outFD = fs.openSync(outFile, 'w');

const buffer = Buffer.alloc(256);

let bytesRead;

do {

    bytesRead = fs.readSync(fileDescriptor, buffer, 0, buffer.length);

    if (bytesRead > 0) {

        inHex = buffer.toString('hex');

        var startTime = process.hrtime();

        var plainStr = rs.KJUR.crypto.Cipher.decrypt(inHex, keyObj, algName);

        var endTime = process.hrtime();

        var diff = (endTime[0] - startTime[0]) * 1000000000 + endTime[1] - startTime[1];

        var outBuffer = Buffer.alloc(4);
        outBuffer.writeInt32LE(diff, 0);
        fs.writeSync(outFD, outBuffer);
    }
} while (bytesRead === buffer.length);

fs.closeSync(fileDescriptor);
fs.closeSync(outFD);

It can be used in similar way as the python reproducer but in the extract step you need to additionally specify --binary 4.

@kjur
Copy link
Owner

kjur commented Nov 21, 2023

@tomato42 , thank you for your report. I'll investigate and try to fix it.

@kjur
Copy link
Owner

kjur commented Jan 16, 2024

Hi @tomato42 , I've just released jsrsasign 11.0.0. RSA and RSAOAEP encryption/decryption functions have been removed. I'm talking with Synk for CVE number coordination and I'll publish security advisory for it. Thank you.

@kjur
Copy link
Owner

kjur commented Jan 17, 2024

Its security advisory is published.
GHSA-rh63-9qcf-83gf

@kjur kjur closed this as completed Jan 17, 2024
kyeah pushed a commit to CMSgov/dpc-app that referenced this issue Apr 2, 2024
<p>This PR was automatically created by Snyk using the credentials of a
real user.</p><br /><h3>Snyk has created this PR to upgrade jsrsasign
from 11.0.0 to 11.1.0.</h3>

:information_source: Keep your dependencies up-to-date. This makes it
easier to fix existing vulnerabilities and to more quickly identify and
fix newly disclosed vulnerabilities when they affect your project.
<hr/>

- The recommended version is **1 version** ahead of your current
version.
- The recommended version was released **2 months ago**, on 2024-02-01.


<details>
<summary><b>Release notes</b></summary>
<br/>
  <details>
    <summary>Package name: <b>jsrsasign</b></summary>
    <ul>
      <li>
<b>11.1.0</b> - <a
href="https://snyk.io/redirect/github/kjur/jsrsasign/releases/tag/11.1.0">2024-02-01</a></br><ul>
<li>Changes from 11.0.0 to 11.1.0 (2024-Feb-01)
<ul>
<li>src/crypto.js
<ul>
<li>restore KJUR.crypto.Cipher class without RSA and RSAOAEP
encryption/decryption support</li>
</ul>
</li>
</ul>
</li>
</ul>
      </li>
      <li>
<b>11.0.0</b> - <a
href="https://snyk.io/redirect/github/kjur/jsrsasign/releases/tag/11.0.0">2024-01-16</a></br><ul>
<li>Changes from 10.9.0 to 11.0.0 (2024-Jan-16)
<ul>
<li>remove RSA PKCS#1.5 end OAEP encryption/decryption for Marvin attack
(<a class="issue-link js-issue-link" data-error-text="Failed to load
title" data-id="2003900052" data-permission-text="Title is private"
data-url="kjur/jsrsasign#598"
data-hovercard-type="issue"
data-hovercard-url="/kjur/jsrsasign/issues/598/hovercard"
href="https://snyk.io/redirect/github/kjur/jsrsasign/issues/598">#598</a>)</li>
<li>src/crypto.js
<ul>
<li>remove KJUR.crypto.Cipher class for RSA and RSAOAEP
encryption/decryption</li>
</ul>
</li>
<li>ext/{rsa,rsa2}.js<br>
remove encrypt/decrypt/encryptOAEP/decryptOAEP for RSAKey class</li>
</ul>
</li>
</ul>
      </li>
    </ul>
from <a
href="https://snyk.io/redirect/github/kjur/jsrsasign/releases">jsrsasign
GitHub release notes</a>
  </details>
</details>


<details>
  <summary><b>Commit messages</b></summary>
  </br>
  <details>
    <summary>Package name: <b>jsrsasign</b></summary>
    <ul>
<li><a
href="https://snyk.io/redirect/github/kjur/jsrsasign/commit/58bb24192f501927014b67911bbde8ef27532319">58bb241</a>
11.1.0 release</li>
<li><a
href="https://snyk.io/redirect/github/kjur/jsrsasign/commit/726c216efacbaa42461d5c8d2ccdefc303ed1fdd">726c216</a>
update readme</li>
<li><a
href="https://snyk.io/redirect/github/kjur/jsrsasign/commit/3f1def8b37e782c7c5b33fadd5636e21227ecf1f">3f1def8</a>
update readme</li>
    </ul>

<a
href="https://snyk.io/redirect/github/kjur/jsrsasign/compare/d73befc129a1a344fa7dc3f672a9b813528fb197...58bb24192f501927014b67911bbde8ef27532319">Compare</a>
  </details>
</details>
<hr/>

**Note:** *You are seeing this because you or someone else with access
to this repository has authorized Snyk to open upgrade PRs.*

For more information: <img
src="https://api.segment.io/v1/pixel/track?data=eyJ3cml0ZUtleSI6InJyWmxZcEdHY2RyTHZsb0lYd0dUcVg4WkFRTnNCOUEwIiwiYW5vbnltb3VzSWQiOiIxZDA3MGQzNC1iOTk1LTRjNDMtYWY0OS0xYjM0YzY3YzYxYWIiLCJldmVudCI6IlBSIHZpZXdlZCIsInByb3BlcnRpZXMiOnsicHJJZCI6IjFkMDcwZDM0LWI5OTUtNGM0My1hZjQ5LTFiMzRjNjdjNjFhYiJ9fQ=="
width="0" height="0"/>

🧐 [View latest project
report](https://app.snyk.io/org/oeda/project/e1f69e43-ca23-488e-a32f-15f5c4b559f3?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🛠 [Adjust upgrade PR
settings](https://app.snyk.io/org/oeda/project/e1f69e43-ca23-488e-a32f-15f5c4b559f3/settings/integration?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🔕 [Ignore this dependency or unsubscribe from future upgrade
PRs](https://app.snyk.io/org/oeda/project/e1f69e43-ca23-488e-a32f-15f5c4b559f3/settings/integration?pkg&#x3D;jsrsasign&amp;utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr#auto-dep-upgrades)

<!---
(snyk:metadata:{"prId":"1d070d34-b995-4c43-af49-1b34c67c61ab","prPublicId":"1d070d34-b995-4c43-af49-1b34c67c61ab","dependencies":[{"name":"jsrsasign","from":"11.0.0","to":"11.1.0"}],"packageManager":"npm","type":"auto","projectUrl":"https://app.snyk.io/org/oeda/project/e1f69e43-ca23-488e-a32f-15f5c4b559f3?utm_source=github&utm_medium=referral&page=upgrade-pr","projectPublicId":"e1f69e43-ca23-488e-a32f-15f5c4b559f3","env":"prod","prType":"upgrade","vulns":[],"issuesToFix":[],"upgrade":[],"upgradeInfo":{"versionsDiff":1,"publishedDate":"2024-02-01T22:43:20.799Z"},"templateVariants":[],"hasFixes":false,"isMajorUpgrade":false,"isBreakingChange":false,"priorityScoreList":[]})
--->

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants