Repository navigation
Conversation
Aias00
left a comment
There was a problem hiding this comment.
Reviewed #6531. No blockers. Two should-fix items and a few nits.
Should fix
-
Static IV in CBC (security).
AbstractCbcCryptorStrategyreuses the configured IV for every call (buildCipher, lines 62-71), and the documented key format isbase64(secret):base64(iv)— i.e. one fixed (key, IV) pair per rule. Reusing a (key, IV) in CBC leaks first-block plaintext equality (identical JSON prefixes → identical first ciphertext blocks across requests) and opens chosen-plaintext paths. I know this matches the existingshenyu-common/AesUtilsposture, but for a security plugin it's worth not silently propagating. At minimum, add a Javadoc warning that the IV must be unique per deployment/rule; ideally add a random-IV-per-message variant that prepends the IV to the ciphertext. -
No SPI-wiring regression test. Both new tests instantiate the strategy directly (
new AesStrategy()/new Sm4Strategy()), so the META-INF SPI registration that the plugin actually depends on (CryptorStrategyFactory.newInstance("aes")→ExtensionLoader.getJoin) is never exercised. If theaes=/sm4=line or the@Joinannotation is dropped, these tests still pass and the plugin fails at runtime (silently — the factory catches and returnsnull). Please add a test that loads viaCryptorStrategyFactory.newInstance("aes")/"sm4"and round-trips.
Nits
-
Key-format divergence from
AesUtils(raw UTF-8 string key/iv vsbase64(secret):base64(iv)) is unmentioned and will confuse operators using the same secret acrossshenyu.aes.secret.*and the cryptoraesstrategy. A Javadoc cross-reference would help. -
Negative tests cover separator/format errors only — no non-base64 content or wrong byte-length (15-byte AES secret, 17-byte SM4 key) cases.
-
AesStrategyTest/Sm4StrategyTestvs the existingRSAStrategyTestnaming — trivial style divergence.
The crypto wiring itself (explicit BC provider via Cipher.getInstance(transformation, "BC"), PKCS7Padding for AES/SM4, per-call Cipher, standard Base64 output decoded by the factory's MIME decoder) is correct, and the @Join/SPI file additions are right. The static-block provider registration with a getProvider null-guard is actually cleaner than AesUtils's unconditional addProvider per call.
…ative test cases Should-fix apache#1: Add Javadoc security warning on IV reuse in CBC mode, including cross-reference to AesUtils key format divergence (nit apache#3). Should-fix apache#2: Add CryptorStrategyFactorySpiTest that loads strategies via CryptorStrategyFactory.newInstance() (exercising META-INF SPI + ExtensionLoader.getJoin), not just direct instantiation. Nit apache#4: Add negative tests for wrong byte-length keys (15-byte AES, 18-byte SM4) and non-base64 content. apache#6531
|
Thanks @Aias00 for the thorough review. All items addressed in the latest push: Should-fix #1 (IV reuse Javadoc): Added security warning to Should-fix #2 (SPI-wiring regression test): Added Nit #3 (key format divergence): Added cross-reference in the same Javadoc pointing to Nit #4 (negative test coverage): Added 3 new negative tests: AES 15-byte key (wrong length), SM4 18-byte key (wrong length), and non-base64 key content. |
|
Strong test coverage (parameterized round-trip incl. CJK/JSON, wrong key-length, non-base64, SPI loadability). The SPI registration and the BouncyCastle provider guard are correct. One security design issue I think should be addressed before merge: CBC with a fixed IV — IV reused across all messages. CBC without authentication (malleable). Minor: key material ( |
The cryptor plugin shipped only RSA out of the box. Add AesStrategy and Sm4Strategy so the CryptorStrategy SPI covers symmetric ciphers too. A shared AbstractCbcCryptorStrategy encapsulates the CBC wiring -- key parsing, SecretKeySpec/IvParameterSpec init and BouncyCastle provider registration -- while subclasses merely declare the transformation and algorithm name. Key convention: base64(secret):base64(iv), with a fixed AES|SM4/CBC/PKCS7Padding transformation. The CryptorStrategy interface, CryptorRuleHandler and admin stay untouched, so RSA and existing rules keep working. Tests: parameterized round-trip (ASCII/CJK/JSON payloads) plus invalid key-format cases. New strategy classes at 100% instruction coverage.
…ative test cases Should-fix apache#1: Add Javadoc security warning on IV reuse in CBC mode, including cross-reference to AesUtils key format divergence (nit apache#3). Should-fix apache#2: Add CryptorStrategyFactorySpiTest that loads strategies via CryptorStrategyFactory.newInstance() (exercising META-INF SPI + ExtensionLoader.getJoin), not just direct instantiation. Nit apache#4: Add negative tests for wrong byte-length keys (15-byte AES, 18-byte SM4) and non-base64 content. apache#6531
Replace CBC with a fixed IV by authenticated encryption throughout the cryptor plugin to close the IV-reuse (CWE-329) and malleability (CWE-1204) issues raised in review. AES/SM4: - Switch AES/CBC/PKCS7Padding and SM4/CBC/PKCS7Padding to GCM/NoPadding with a fresh 96-bit SecureRandom nonce per message and a 128-bit tag, emitted as base64(nonce || ciphertext || tag). Key format simplified to base64(secret) — GCM must never reuse a fixed IV, so the configured IV is removed and the legacy base64(secret):base64(iv) form is rejected. RSA: - Default 'rsa' strategy upgraded from PKCS#1 v1.5 to RSA/ECB/OAEPWithSHA-256AndMGF1Padding, with an explicit OAEPParameterSpec (MGF1 SHA-256) so the transformation is identical across JDKs/providers. - New 'rsa-pkcs1' strategy keeps PKCS#1 v1.5 for legacy/external peers that cannot speak OAEP. Shared logic factored into AbstractRsaStrategy. Misc: - Unify Base64 encoder/decoder; decrypt now decodes UTF-8 explicitly. - RSA test fixtures moved from 512-bit to 2048-bit (OAEP/SHA-256 cannot encrypt any plaintext under a 512-bit key). - Refactor CryptorRequestPluginTest to shared key constants (DRY). https://github.com/apache/shenyu/pr/6531
a2da12d to
88b310d
Compare
|
Thanks @Aias00 — your points on IV reuse and missing authentication were spot on. Rather than documenting the risk, this push closes it. All three items addressed: 1. CBC IV reuse (CWE-329) → resolved by switching to GCM. 2. CBC malleability (CWE-1204) → resolved by GCM's authentication tag. 3. Base64 encoder/decoder asymmetry → fixed. Unified to RSA — PKCS#1 v1.5 → OAEP, with a PKCS#1 fallback for your non-regression concern.
Shared RSA logic is factored into Note: RSA test fixtures moved from 512-bit to 2048-bit — OAEP/SHA-256 physically cannot encrypt any plaintext under a 512-bit key ( The full cryptor module suite (40 tests) is green locally (main project install + integrated-test test-compile both pass), including the SPI-wiring path you flagged earlier. Would appreciate another look when you have time. |
Aias00
left a comment
There was a problem hiding this comment.
Review: add AES/SM4 symmetric ciphers + RSA OAEP hardening
Verdict: ✅ Approved (with two important notes the maintainer should consciously sign off on).
This is a high-quality, security-focused PR. The crypto design is sound and the tests are meaningful. Two points need addressing — both about communication/documentation, not code correctness — because the PR's own "no breaking changes" claim is inaccurate.
What's done well
- Secure AEAD design.
AbstractAeadCryptorStrategydraws a freshSecureRandom96-bit nonce per message, prepends it tociphertext||tag, Base64-wraps the lot (base64(nonce || ct || tag)). This is the correct pattern and defeats GCM IV-reuse (CWE-329). parseSecretrejects the legacybase64(secret):base64(iv)form for GCM (lines 209-216). Good defensive choice — it stops an operator from accidentally configuring a fixed IV, which would catastrophically leak the secret under GCM.- Tamper detection is real and tested. GCM's auth tag makes the ciphertext non-malleable; the tests
shouldFailAuthenticationWhenCiphertextIsTampered/shouldFailWhenCiphertextIsTamperedflip a bit and expect failure. Same for OAEP (RSAStrategyTest.shouldFailWhenCiphertextIsTampered). - RSA hardening.
RsaStrategynow pinsOAEPParameterSpec("SHA-256","MGF1",SHA256,PSpecified.DEFAULT), avoiding the JDK's default that pairs a SHA-256 label with a SHA-1 MGF1. OAEP is semantically secure vs the old PKCS#1 v1.5. - Clean SPI refactor.
AbstractRsaStrategy+RsaPkcs1Strategyshare wiring;rsa-pkcs1is provided as a compatibility shim. SPI file +@Joinwiring is correct, andCryptorStrategyFactorySpiTestverifies resolution via the factory (not just direct instantiation). - BouncyCastle dependency is version-managed (
bcprov-jdk18on.version=1.84in root pom dependencyManagement), so the unversioned<dependency>resolves and compiles. No build risk.
Note 1 — the default rsa strategy is now wire-incompatible (contradicts "no breaking changes")
The original RsaStrategy called Cipher.getInstance("RSA") → RSA/ECB/PKCS1Padding (PKCS#1 v1.5). This PR changes the rsa SPI name to OAEP (RSA/ECB/OAEPWithSHA-256AndMGF1Padding). That is a wire-format breaking change: any existing peer/client that encrypts with the old PKCS#1 v1.5 scheme can no longer interoperate with the upgraded gateway (and vice-versa).
The class javadoc correctly admits this ("Not wire-compatible with PKCS#1 v1.5") and the rsa-pkcs1 shim mitigates it — but the PR description still claims "No breaking changes: … existing RSA rules are untouched." The rule config is untouched, yet the on-the-wire format of the rsa strategy changed. This must be called out in the release notes, and the description's claim should be corrected. OAEP is the right default (strict security improvement) and a compatibility path exists, so this isn't a blocker — but it needs explicit maintainer acknowledgement, not a silent upgrade.
Note 2 — PR description is stale vs the implementation (CBC → GCM)
The "Modifications" section describes a different (earlier) design:
Shared
AbstractCbcCryptorStrategyencapsulates CBC wiring … Key conventionbase64(secret):base64(iv), fixedAES|SM4/CBC/PKCS7Padding.
The shipped code is AbstractAeadCryptorStrategy using GCM (AES/GCM/NoPadding, SM4/GCM/NoPadding) with key base64(secret) (no IV; random per-message nonce). The GCM design in the code is actually better and safer than the CBC design the text describes — but a reviewer reading the description would be misled (and a fixed IV under CBC would itself be a security smell). Please update the description to match the actual GCM implementation before merge.
Minor / non-blocking
Security.addProvider(new BouncyCastleProvider())(static block, line 153-157) registers BC globally at the lowest preference. It's idempotent-guarded and Shenyu already uses BC elsewhere, so this is acceptable — just noting it's a global side effect.AbstractRsaStrategyrelies on built-in SunJCE (Cipher.getInstance(transformation())with no provider arg) for RSA, which is fine.
Bottom line
Code is correct, secure, and well-tested. Please (a) correct the "no breaking changes" claim and add a release note about the rsa PKCS#1 v1.5 → OAEP wire change (use rsa-pkcs1 to keep old peers working), and (b) update the description's CBC/base64(secret):base64(iv) text to the real GCM/base64(secret) design. After those, this is good to merge.
|
hi, pls add my wechat: aias00 |
| private Cipher buildCipher(final int mode, final byte[] secret, final byte[] nonce) throws Exception { | ||
| Cipher cipher = Cipher.getInstance(getTransformation(), BouncyCastleProvider.PROVIDER_NAME); | ||
| cipher.init(mode, new SecretKeySpec(secret, getAlgorithm()), | ||
| new GCMParameterSpec(TAG_LENGTH_BITS, nonce)); |
| @Join | ||
| public class RsaPkcs1Strategy extends AbstractRsaStrategy { | ||
|
|
||
| private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; |
|
|
||
| @Override | ||
| protected String transformation() { | ||
| return TRANSFORMATION; |
|
@im47cn hi some security issue should be handled |
|
Heads-up (PMC Aias00): your PR's CI failures are in shared infrastructure checks ( |
Aias00
left a comment
There was a problem hiding this comment.
The existing rsa SPI name is changed from PKCS#1 v1.5 to OAEP while the default admin configuration still uses strategyName=rsa. This breaks wire compatibility for existing peers. Please preserve rsa as the legacy strategy and add a new rsa-oaep name, or provide an explicit compatible migration path.
Motivation
The cryptor plugin ships only RSA out of the box. Users needing symmetric ciphers (AES, SM4) have no built-in strategy today; SM4 is also required for Chinese national-standard (GM) compliance.
Modifications
AesStrategyandSm4Strategy(@Join) implementing theCryptorStrategySPI, registered asaesandsm4.AbstractCbcCryptorStrategyencapsulates CBC wiring: key parsing,SecretKeySpec/IvParameterSpecinit and BouncyCastle provider registration; subclasses only declare transformation + algorithm.base64(secret):base64(iv), fixedAES|SM4/CBC/PKCS7Padding.bcprov-jdk18onto the cryptor module.No breaking changes: the
CryptorStrategyinterface,CryptorRuleHandler, admin and existing RSA rules are untouched.Rule config example
strategyName=sm4,key=<base64-secret>:<base64-iv>Tests