RSA Decrypt: "URIError: malformed URI sequence" when piping From Hex → RSA Decrypt (OAEP)
- Dominant language
- JavaScript
- Stars
- 35.8k
- Forks
- 4.1k
- Avg merge
- 2d 26m
- Merged PRs (30d)
- 33
Description
## Description
The **RSA Decrypt** operation in CyberChef v10/v11 fails with `URIError: malformed URI sequence` when attempting to decrypt hex-encoded RSA-OAEP ciphertext piped from a "From Hex" operation.
## Environment
- CyberChef version: v10.19.4 AND v11.0.0 (both affected)
- Browser: Chrome/Firefox (reproducible across browsers)
- OS: Windows 10/11
## Steps to Reproduce
1. Open CyberChef
2. Add **From Hex** operation
3. Paste an RSA-OAEP-SHA256 encrypted ciphertext in hex format (e.g., 512 hex chars = 256 bytes for RSA-2048)
4. Add **RSA Decrypt** operation
5. Set **Encryption Scheme** to `RSA-OAEP`
6. Set **Message Digest Algorithm** to `SHA-256`
7. Paste a valid RSA private key (PEM format)
8. Click **Bake**
**Actual result:**
```
URIError: malformed URI sequence
```
**Expected result:**
The decrypted output (binary or hex).
## Root Cause Analysis
Two interrelated issues in the RSA Decrypt operation implementation (`Ciphers.js`):
### Issue 1: `inputType="string"` incompatible with forge.js decode chain
The operation declares `inputType="string"` and passes the input directly to forge.js:
```javascript
// Ciphers.js - RSA Decrypt run method
this.inputType = "string"
this.outputType = "string"
run: function(e, t) {
// ...
var o = rt().pki.decryptRsaPrivateKey(n, i).decrypt(e, a, {md: vn[s].create()});
return rt().util.decodeUtf8(o);
}
```
Forge.js's `key.decrypt(data, scheme, options)` expects `data` as a **byte string** (each character = one byte, 0x00-0xFF). When the pipeline is:
```
From Hex → ArrayBuffer → [type coercion] → String → RSA Decrypt
```
The intermediate ArrayBuffer→String conversion in CyberChef's internal pipeline triggers UTF-8 validation. Binary bytes outside valid UTF-8 sequences cause the conversion to fail, manifesting as `URIError: malformed URI sequence` (the error surfaces from CyberChef's URL recipe encoding layer).
### Issue 2: Output `decodeUtf8()` fails on non-UTF-8 decryption results
The operation always calls `rt().util.decodeUtf8(o)` on the decrypted output. RSA-OAEP decryption often produces raw binary keys (e.g., AES keys), which are not valid UTF-8. This should either:
- Allow `outputType` to be `byteArray` with a "To Hex" post-processing option
- Or handle the UTF-8 decode failure gracefully
## Proposed Fix
1. Change RSA Decrypt's `inputType` to `"byteArray"` (or `"ArrayBuffer"`) to accept binary input directly, avoiding the broken string coercion path
2. Change `outputType` to `"byteArray"` and let users add `To Hex` themselves for display
3. Or: add an "Input format" parameter (Hex/Raw) similar to other cipher operations (AES Decrypt, DES Decrypt)
## Workaround
Currently no workaround within CyberChef. Users must use external tools (Python, OpenSSL) for RSA-OAEP decryption.
## Example Data for Testing
**Private Key (PKCS#8):**
```
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBkZUqED7P4Twf
FwwtkW45z2QYpJSfKtwlakSeanlRODnrENaAUf1qhX0jS/E0yczTwCG+NoKFOLLm
XkXYy6krTzE3BVtR40gg9EvqUAOyoiDAOlbs2mhpydxOaqllIYGUO81z3hyjc66g
B0+MlFlOLzZ08QWtQVjER4rFGuGSvNwG1cwCtvN1jTiPAdfU/W9t1ggvWzpwK18y
Np2tw3vm1QUV+ULtcViD4GrJQbKRMLVvD9YAc+aELStqZYiQ0yWVlRPpF07qq/p7
lWfGau91wWlHviHTPEW4BgugX8vTibuOJNUp54RGuN1S9A137cDMg1SHalcyjcua
iQ77Jp0PAgMBAAECggEACFemZpwxoNLzvOFI6JPafMpX5Yn+T8fQmho03+D13o6+
TEe6/ufJtLQRGxrUR/KkjcG7ko+V23kAmNYaS4gnf9LXa6gi8eoKO0VcGjqdli7P
m4lIIsgc9OY6xPRq3Y1uoL1dEu/RKyg6r/Hwtz3ThX+aaLrUhE2LLlZpACqy6xh+
bRpzhgelnPaJ9mAXzJr0nEYOqC/7nyBWNGICrknTWZuE04hKhrLI7UmmiIKmZF5f
SCW3LuTp2cjyVJm1hcNnmnJTUkAwApEpSsSxFvjhK1bRoxbCsnBGIIrO8o6MCZf3
NhI17PbY/8yy2GWXewfvXhyuagP0xUy8zKXY/8upeQKBgQDnocLDLW5D7aZYuwCs
XhotHIDOMhgDMRPpPoBt8JkEa5geHWbS6cNS51A8hi7lXSLvCfWFQ5cGTwxTyFRN
GHCIuHhC1U6wd1XP3Xi3hIdljIxV7Q8PuZ9CJlHC9/Cu8SjwVUTrGt7EhkYiMgK7
7dkIwVz60KuwqeWy0aTcy/KDaQKBgQDV7rcp9k4cX8gn2IgFBFi/mbxJDtVK0Fa9
WlY+NqmGcTwMFOKN1ZvWkK7U7RbMYsw7W7jlxyQjcOu4LaR1Y4uuxxg3ID7ItXwn
0HYom0IaotR11ovsbEaKrZSbjmwRZ/l8ruOhcZ7vdT+CPwoSt8TVOVL8bpxRrQAv
f9NqRliltwKBgG6SnLu5UzrgFpmi42ZlIY/JXH+SED5tzjh42qwgv5sJlbtCg9RJ
PTG1NGtADuD0/fkoQukT4+NiFttj9UI8WXQaw2X8F61Luk4ZRkgs3smON2vJV3hF
Pw4/5qXw4BdTDhz0R4sH77HW+2HVh9KYbxOr4qvksyEJaZpcU5wHS8SJAoGARTnc
7Wg1eHsKEtK/mRgB++YshluVa4MlPlq4I6OekdGcg7BSa2Ee73ycBmy9/t9NhTu2
Biy9pfZJYKzsVcwjjCgCzvvRNTN8/Ik5YwRyjJn6NDN7zcJvxTpMJ1Yb5DoIAm+5
WymgK45+QZBSmyH6QKEvGF5WmRtpPvWXHQGsd9sCgYB1U5Zgb2xf9PLs5eBI3lNc
1jKzXhsFBdMgCDM+/eQmoe2m/p+tV9tE1xIvtdm6CEhvjorgryx0dp8eldQo5Urb
NRS5V1Pds7SIg7n5A+Lqx3DQSW7WBg+/HxIfowqBmVVeOw54A1KAi93r7tzHRCqm
Gyfsg2sB9Y0VQspb36o9hg==
-----END PRIVATE KEY-----
```
**Encrypted Data (hex):**
```
bf130206572b4091a8b29295896d84de3d445c071cdf5646b662fb76cbe9ab905fc23cca1612926d4d05fafde3bb11f5760af0bac45ce880d3fb9b56ab3f159f31049723a5b03d0262630f2f4d984aa789d1b3c9839ead4c04eefe1adec9688f61bc5c9e9a9a25c65273169e0262910a94eeca1a0cdfceca0bdb358a42ae118df0b86903566360c23fe7ea0062b8bec56e15881747ab8286b12e12ef77d5e4dbfc5f3579b8cc4235065425da51cbb02f90d4701133aa489850e4281d45c33d30ddbf492f8ab74c0532174431d39e95e1d0be77142e6863528de82d960d81e61051b2e428e30b106d7aeed1ce77c9e99072094de5d56332fcf586a36a2c31db10
```
**Expected Decryption Output (hex):**
```
f89766d163f006af7d37beeee64ae9e2b071abb64fe2e2fb36e8e49ee7b5b061
```
Contributor guide
Research direction
Start in Ciphers.js at the RSA Decrypt run method and reproduce the From Hex → RSA Decrypt (OAEP/SHA-256) pipeline with the supplied key and ciphertext. Trace the binary input and decrypted output handling, then verify the operation produces the supplied expected plaintext hex without the URIError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100