Skip to content

Conversation

@onahprosper
Copy link
Collaborator

@onahprosper onahprosper commented Jan 13, 2026

Description

This PR implements hybrid encryption (AES-256 + RSA-2048) for the message hash functionality to support larger payloads while maintaining security.

Key Changes:

  • Replaced RSA-only encryption with hybrid approach (AES-256 for data, RSA-2048 for key encryption)
  • Increased maximum payload capacity from 245 bytes to 500 bytes
  • Added `MESSAGE_HASH_MAX_SIZE` configuration parameter (default: 500 bytes)
  • Implemented payload size validation before encryption
  • Enhanced error messages for size limit violations

Benefits:

  • Enables encryption of larger order recipient data (2x capacity increase)
  • Better performance for large payloads (AES is faster than RSA for bulk data)
  • Industry-standard security approach used in TLS/SSL
  • Maintains backward compatibility with existing encrypted data

References

closes #647
This change addresses the limitation of RSA-2048 encryption which could only handle payloads up to 245 bytes.

Testing

  • This change adds test coverage for new/changed/fixed functionality

Test Coverage:

  • ✅ Basic encryption and decryption with hybrid approach
  • ✅ Large payload encryption (under 500 bytes limit)
  • ✅ 500-byte limit enforcement (success and failure cases)
  • ✅ Backward compatibility tests
  • ✅ Nonce randomness verification
  • ✅ Tampered message detection
  • ✅ Invalid input handling

Manual Testing:
All tests pass successfully:
```bash
cd utils/crypto && go test -v -run TestGetOrderRecipientFromMessageHash
```

Environment:

  • Go 1.25.0
  • Platform: Linux

Checklist

  • I have added documentation and tests for new/changed/fixed functionality in this PR
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not `main`

By submitting a PR, I agree to Paycrest's Contributor Code of Conduct and Contribution Guide.

Summary by CodeRabbit

  • New Features

    • Added configuration parameter MessageHashMaxSize (default: 500) to enforce maximum message payload size.
    • Introduced a hybrid JSON encryption envelope with size-prefixing for large payloads and a backward-compatible fallback to the legacy public-key format.
  • Tests

    • Expanded tests covering encryption/decryption, boundary conditions (including the 500-byte limit), large payloads, tampering/invalid inputs, and backward compatibility.

✏️ Tip: You can customize this high-level summary in your review settings.

- Replace RSA-only encryption with hybrid AES-256 + RSA-2048 approach
- Increase maximum payload capacity from 245 bytes to 500 bytes
- Add MESSAGE_HASH_MAX_SIZE config (default: 500 bytes)
- Implement payload size validation before encryption
- Add comprehensive test coverage for hybrid encryption
- Add tests for 500-byte limit enforcement
- Maintain backward compatibility with decryption

This change enables larger order recipient data while maintaining security through hybrid encryption that combines AES-256 for data encryption and RSA-2048 for key encryption.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Adds a configurable MESSAGE_HASH_MAX_SIZE and implements hybrid encryption (AES-256-GCM payload + RSA-2048 key-wrap) with a 4-byte length-prefixed envelope; updates EncryptOrderRecipient/GetOrderRecipientFromMessageHash to use hybrid format with legacy fallback; adds comprehensive tests for hybrid and legacy cases.

Changes

Cohort / File(s) Summary
Configuration
config/crypto.go
Added MessageHashMaxSize int to CryptoConfiguration; default set via viper.SetDefault("MESSAGE_HASH_MAX_SIZE", 500) and read via viper.GetInt("MESSAGE_HASH_MAX_SIZE").
Hybrid Encryption Implementation
utils/crypto/crypto.go
Added encryptHybridJSON, decryptHybridJSON, isHybridEncrypted, decryptOrderRecipientWithFallback; EncryptOrderRecipient now enforces MessageHashMaxSize and produces envelope [4-byte len][rsa(encKey)][aes-gcm(ciphertext)]; GetOrderRecipientFromMessageHash supports hybrid and legacy RSA formats; added encoding/binary usage.
Tests
utils/crypto/crypto_test.go
Added TestGetOrderRecipientFromMessageHash and TestGetOrderRecipientFromMessageHash_BackwardCompatibility covering basic and hybrid encryption flows, size boundary checks, tampering/invalid inputs, nonce randomness, and legacy compatibility; new imports for test utilities.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Encryptor
    participant JSON_Marshal as "JSON Marshal"
    participant AES as "AES-256-GCM"
    participant RSA as "RSA-2048 OAEP"
    participant Envelope

    Client->>Encryptor: provide data + RSA public key + maxSize
    Encryptor->>JSON_Marshal: marshal data
    JSON_Marshal-->>Encryptor: JSON bytes
    Encryptor->>Encryptor: check size ≤ maxSize
    Encryptor->>AES: generate AES-256 key, encrypt JSON (GCM)
    AES-->>Encryptor: ciphertext + nonce
    Encryptor->>RSA: encrypt AES key with RSA OAEP
    RSA-->>Encryptor: encrypted AES key
    Encryptor->>Envelope: assemble [4-byte len][enc AES key][ciphertext]
    Envelope-->>Client: hybrid encrypted envelope
Loading
sequenceDiagram
    participant Client
    participant Decryptor
    participant EnvelopeParser as "Envelope Parser"
    participant RSA as "RSA-2048 OAEP"
    participant AES as "AES-256-GCM"
    participant JSON_Unmarshal as "JSON Unmarshal"

    Client->>Decryptor: send envelope + RSA private key
    Decryptor->>EnvelopeParser: read 4-byte length, extract enc AES key and ciphertext
    EnvelopeParser-->>Decryptor: segments (encKey, ciphertext)
    Decryptor->>RSA: decrypt encKey -> AES key
    RSA-->>Decryptor: AES key
    Decryptor->>AES: decrypt ciphertext (GCM) using AES key + nonce
    AES-->>Decryptor: plaintext JSON bytes
    Decryptor->>JSON_Unmarshal: unmarshal to object
    JSON_Unmarshal-->>Client: original data structure
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I nibble on bytes in a moonlit patch,
AES keeps the fruit while RSA latches the batch.
Four tiny bytes mark the secret's door,
Hybrid hops onward — secure evermore.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: implementing hybrid encryption with a 500-byte limit for message hash functionality.
Description check ✅ Passed Description covers all template sections: purpose/impacts, references to issue #647, comprehensive testing details, and completed checklist items.
Linked Issues check ✅ Passed All coding objectives from issue #647 are met: hybrid AES-256-GCM + RSA-2048 implementation, 500-byte limit enforcement, backward compatibility, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes directly support hybrid encryption implementation: config field addition, core crypto functions, and targeted test suite with no extraneous modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
utils/crypto/crypto_test.go (2)

182-220: Consider using configured limit for consistency.

Similar to the previous test, line 212 hardcodes 500 for the size assertion. For maintainability, consider using cryptoConf.MessageHashMaxSize.

The error message assertion at line 217 checking for "payload too large" is appropriate.

Suggested improvement
-		assert.Greater(t, jsonSize, 500, "payload should exceed 500 bytes for this test")
+		assert.Greater(t, jsonSize, cryptoConf.MessageHashMaxSize, "payload should exceed configured limit for this test")

396-407: Errors silently ignored in test setup could hide failures.

Lines 397 and 407 ignore potential errors from encryption functions. If encryption fails during test setup, the test would proceed with invalid data and produce confusing failures.

Suggested fix
 		// Create legacy encrypted message
-		legacyEncrypted, _ := PublicKeyEncryptJSON(legacyData, publicKey)
+		legacyEncrypted, err := PublicKeyEncryptJSON(legacyData, publicKey)
+		assert.NoError(t, err, "legacy encryption setup should succeed")
 		legacyHash := base64.StdEncoding.EncodeToString(legacyEncrypted)

 		// Create new hybrid encrypted message
 		newOrder := &ent.PaymentOrder{
 			AccountIdentifier: "HYBRID456",
 			AccountName:       "Hybrid User",
 			Institution:       "Hybrid Bank",
 			Memo:              "Hybrid format",
 		}
-		hybridHash, _ := EncryptOrderRecipient(newOrder)
+		hybridHash, err := EncryptOrderRecipient(newOrder)
+		assert.NoError(t, err, "hybrid encryption setup should succeed")

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04577e8 and 8d0e70b.

📒 Files selected for processing (1)
  • utils/crypto/crypto_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
utils/crypto/crypto_test.go (1)
utils/crypto/crypto.go (3)
  • EncryptOrderRecipient (359-388)
  • GetOrderRecipientFromMessageHash (422-445)
  • PublicKeyEncryptJSON (156-170)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🔇 Additional comments (5)
utils/crypto/crypto_test.go (5)

3-11: LGTM!

Imports are appropriate for the new test functionality covering encoding, JSON serialization, string manipulation, and the entity types.


52-138: LGTM!

Good coverage of the basic encryption/decryption flow, provider edge case, and large payload handling with hybrid encryption. The tests properly verify round-trip data integrity.


222-293: LGTM!

Good coverage of edge cases including small metadata, invalid base64 handling, tamper detection via bit-flipping, and empty field handling. The tamper test correctly verifies that integrity checks detect modifications.


295-320: LGTM!

Excellent test for verifying nonce randomness. It correctly validates that:

  1. Same input produces different ciphertext (line 309)
  2. Decrypted nonces are non-empty (lines 314, 318)
  3. Nonces differ between encryptions (line 319)

This ensures the cryptographic nonce generation is working correctly.


331-361: LGTM!

Well-designed backward compatibility test that properly simulates the legacy RSA-only format by directly using PublicKeyEncryptJSON and verifying that GetOrderRecipientFromMessageHash can still decrypt it via the fallback mechanism.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @utils/crypto/crypto_test.go:
- Around line 135-175: The test currently compares jsonSize to a hardcoded 500;
update the test to use the actual configured limit by referencing
cryptoConf.MessageHashMaxSize (or set cryptoConf.MessageHashMaxSize explicitly
in the test) before the size check so the conditional and expectations match
EncryptOrderRecipient's behavior; ensure you import or access the same crypto
configuration used by EncryptOrderRecipient and use that value in the if
jsonSize <= ... check and any log/assert messages so
GetOrderRecipientFromMessageHash/EncryptOrderRecipient behavior is tested
consistently.
🧹 Nitpick comments (4)
utils/crypto/crypto.go (3)

315-318: Minor: Potential integer overflow when casting uint32 to int on 32-bit systems.

On 32-bit systems, if keyLen exceeds math.MaxInt32, the cast to int would produce a negative value, potentially bypassing the length check. In practice, RSA-2048 output is 256 bytes, making this unlikely, but defensive coding would add an upper bound check.

🛡️ Optional defensive check
 	// Extract encrypted key
 	keyLen := binary.BigEndian.Uint32(encrypted[0:4])
+	if keyLen > 1024 { // RSA-4096 max is 512 bytes; 1024 is generous upper bound
+		return nil, fmt.Errorf("invalid key length: %d", keyLen)
+	}
 	if len(encrypted) < int(4+keyLen) {
 		return nil, fmt.Errorf("invalid encrypted data length")
 	}

402-402: Inconsistent config access pattern.

Line 386 uses the cached cryptoConf variable, but line 402 calls config.CryptoConfig() directly. While functionally equivalent, this inconsistency could lead to confusion and potential issues if caching behavior matters.

♻️ Suggested fix for consistency
 	// Decrypt with the private key of the aggregator
-	message, err := decryptHybridJSON(messageCipher, config.CryptoConfig().AggregatorPrivateKey)
+	message, err := decryptHybridJSON(messageCipher, cryptoConf.AggregatorPrivateKey)

407-416: Consider avoiding double JSON serialization.

The current approach marshals the interface{} back to JSON bytes, then unmarshals into the typed struct. This works but is inefficient. A cleaner approach would be to have decryptHybridJSON accept a destination pointer or return raw bytes.

♻️ Alternative approach (if performance matters)
// Option: Return raw bytes from decryptHybridJSON and unmarshal directly
func decryptHybridJSONBytes(encrypted []byte, privateKeyPEM string) ([]byte, error) {
    // ... same decryption logic ...
    return plaintext, nil  // Return bytes instead of unmarshaling
}

// Then in GetOrderRecipientFromMessageHash:
plaintext, err := decryptHybridJSONBytes(messageCipher, cryptoConf.AggregatorPrivateKey)
if err != nil {
    return nil, fmt.Errorf("failed to decrypt message hash: %w", err)
}
var recipient *types.PaymentOrderRecipient
if err := json.Unmarshal(plaintext, &recipient); err != nil {
    return nil, err
}
utils/crypto/crypto_test.go (1)

47-73: Good coverage for basic flow, but metadata assertion is missing.

The test verifies AccountIdentifier, AccountName, Institution, and Memo, but doesn't assert that Metadata round-trips correctly despite being set in the test order.

🧪 Add metadata assertion
 		assert.Equal(t, order.Institution, recipient.Institution)
 		assert.Equal(t, order.Memo, recipient.Memo)
+		assert.Equal(t, "TEST123", recipient.Metadata["reference"])
+		assert.Equal(t, "Test transaction", recipient.Metadata["note"])
 	})
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1b237c and d851171.

📒 Files selected for processing (3)
  • config/crypto.go
  • utils/crypto/crypto.go
  • utils/crypto/crypto_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
utils/crypto/crypto_test.go (1)
utils/crypto/crypto.go (2)
  • EncryptOrderRecipient (363-392)
  • GetOrderRecipientFromMessageHash (395-418)
utils/crypto/crypto.go (1)
config/crypto.go (1)
  • CryptoConfig (20-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🔇 Additional comments (6)
utils/crypto/crypto.go (2)

256-306: LGTM! Hybrid encryption implementation is well-designed.

The encryptHybridJSON function correctly implements AES-256-GCM with RSA-2048 key wrapping:

  • Size validation occurs after JSON marshaling (correct order)
  • Cryptographically secure random generation for both AES key and nonce
  • Proper envelope format with length-prefixed RSA-encrypted key

385-386: LGTM! Clean integration with the new hybrid encryption.

The EncryptOrderRecipient function correctly delegates to encryptHybridJSON with the configured public key and max size limit.

utils/crypto/crypto_test.go (3)

247-270: Excellent tampering detection test.

This test correctly validates that AES-GCM's authenticated encryption detects modifications to the ciphertext. The bit-flip approach is a good way to verify integrity protection.


290-315: Good nonce randomness verification.

Testing that consecutive encryptions produce different outputs and different nonces confirms the cryptographic non-determinism is working correctly.


46-315: Remove comment - backward compatibility is not a PR requirement.

The PR objectives, as shown in the commit message, specify only "implement hybrid encryption for message hash with 500-byte limit" with no mention of backward compatibility. The implementation correctly focuses on the hybrid encryption format. The test suite appropriately covers the new functionality without needing backward compatibility tests.

config/crypto.go (1)

16-16: Configuration is correct; runtime validation already handles edge cases.

The MessageHashMaxSize configuration follows the established pattern in this file, and the default of 500 bytes is reasonable. The code already validates this at runtime in encryptHybridJSON(): any payload exceeding the limit returns an error rather than silently proceeding. This behavior is tested and intentional—no additional validation is needed at config time.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @utils/test/test.env:
- Around line 21-24: Summary: Committed RSA private keys in test.env are a
security risk and must be removed; replace with a test-safe mechanism. Fix:
delete the hard-coded AGGREGATOR_PRIVATE_KEY and AGGREGATOR_PUBLIC_KEY from the
committed test.env and instead (a) update tests that reference
AGGREGATOR_PRIVATE_KEY / AGGREGATOR_PUBLIC_KEY to obtain keys from environment
variables or a test fixture that generates ephemeral RSA key pairs at setup
time, (b) add a committed test.env.example (or README note) showing the variable
names but not real keys, and (c) ensure the real test.env or any file containing
private keys is gitignored or excluded from commits; also add a brief comment
near AGGREGATOR_PRIVATE_KEY/AGGREGATOR_PUBLIC_KEY in tests explaining they must
never be hard-coded and keep any CI provisioning logic to inject real keys
securely.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d851171 and 2209e99.

📒 Files selected for processing (1)
  • utils/test/test.env
🧰 Additional context used
🪛 Gitleaks (8.30.0)
utils/test/test.env

[high] 24-24: Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.

(private-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🔇 Additional comments (2)
utils/test/test.env (2)

19-19: HD wallet mnemonic is committed to version control.

Similar to the RSA keys concern, this mnemonic phrase could derive real wallet addresses. Ensure this is a well-known test mnemonic that holds no real value, or consider generating it dynamically during tests.


28-28: This SendGrid API key is a dummy placeholder, not a real credential.

The key SG.RSmzXPz3QpGfIabVecxxNA is only 24 characters long, while authentic SendGrid API keys are always exactly 69 characters. Located in a test environment file alongside other obvious test credentials (test DB password, test mnemonic, test RSA keys), this is a valid placeholder key for testing and does not represent a security risk.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @utils/crypto/crypto_test.go:
- Around line 154-179: The test computes payload size using a local ad-hoc
struct which can drift from the real struct used by EncryptOrderRecipient and
then conditionally skips assertions if size > 500; instead, marshal the actual
value passed into EncryptOrderRecipient (use json.Marshal(order) rather than the
local struct) so the measured size matches the implementation, and replace the
conditional with a hard assertion (e.g., require.LessOrEqual(t, jsonSize, 500))
so the test fails fast if the payload exceeds 500 bytes before calling
EncryptOrderRecipient and GetOrderRecipientFromMessageHash.
🧹 Nitpick comments (1)
utils/crypto/crypto_test.go (1)

52-78: Consider verifying Metadata content after decryption.

The test verifies AccountIdentifier, AccountName, Institution, and Memo, but doesn't verify that the Metadata map is correctly preserved after the round-trip. Adding an assertion like assert.Equal(t, order.Metadata, recipient.Metadata) would strengthen the test.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2209e99 and d4db174.

📒 Files selected for processing (1)
  • utils/crypto/crypto_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🔇 Additional comments (10)
utils/crypto/crypto_test.go (10)

3-11: LGTM!

Imports are appropriate for the test suite requirements.


46-50: LGTM!

The conditional skip for missing RSA keys is a sensible approach for CI tolerance, and the message clearly indicates what's needed.


80-105: LGTM!

Good coverage for the provider edge relationship scenario.


107-138: LGTM!

Good test for hybrid encryption with larger payloads. The metadata length comparison at line 135 could be strengthened to a full equality check, but this is minor.


182-220: LGTM with same struct caveat.

Good test structure—the assert.Greater at line 212 validates the test precondition. The error message check at line 217 properly verifies the failure reason. The same local struct concern applies here but is less critical since the guard assertion catches setup issues.


222-242: LGTM!

Good edge case coverage for minimal metadata.


244-250: LGTM!

Good negative test for invalid input handling.


252-275: LGTM!

Good integrity test verifying that tampered ciphertext is detected. The bit manipulation approach correctly tests the authentication properties of the hybrid encryption scheme.


277-293: LGTM!

Good edge case coverage for empty field handling.


295-320: LGTM!

Excellent test for cryptographic randomness. Verifying that identical inputs produce different ciphertexts is critical for encryption security.

Dprof-in-tech
Dprof-in-tech previously approved these changes Jan 14, 2026
Copy link
Collaborator

@Dprof-in-tech Dprof-in-tech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@utils/crypto/crypto_test.go`:
- Around line 46-51: The skip message in TestGetOrderRecipientFromMessageHash is
misleading; update the t.Skip call to use a clear, accurate message (e.g.,
referencing TestGetOrderRecipientFromMessageHash or missing
AGGREGATOR_PUBLIC_KEY/PRIVATE_KEY) so developers know why this specific test was
skipped; locate the skip in TestGetOrderRecipientFromMessageHash and replace the
text passed to t.Skip with the corrected message.
♻️ Duplicate comments (1)
utils/crypto/crypto_test.go (1)

140-180: Previous feedback on this segment still applies.

The concerns raised in prior reviews remain unaddressed:

  1. The hardcoded 500 should reference cryptoConf.MessageHashMaxSize for consistency with the implementation
  2. The local struct definition may drift from the actual struct used in EncryptOrderRecipient
  3. The conditional if jsonSize <= 500 makes the test unreliable - if the payload happens to exceed 500 bytes, the test passes without verifying anything

Consider using require.LessOrEqual(t, jsonSize, cryptoConf.MessageHashMaxSize) to fail fast if the test setup is wrong, ensuring the test actually exercises the intended path.

🧹 Nitpick comments (2)
utils/crypto/crypto_test.go (2)

182-220: Consider using the configured max size constant.

This test correctly asserts that the payload exceeds 500 bytes before testing. However, the hardcoded 500 values should reference cryptoConf.MessageHashMaxSize for consistency with the implementation. If the configuration changes, this test would need manual updates.

Suggested improvement
 		t.Logf("Payload size: %d bytes (exceeds 500 byte limit)", jsonSize)
-		assert.Greater(t, jsonSize, 500, "payload should exceed 500 bytes for this test")
+		assert.Greater(t, jsonSize, cryptoConf.MessageHashMaxSize, "payload should exceed max size for this test")
 
 		// This should fail due to size limit
 		_, err := EncryptOrderRecipient(order)
 		assert.Error(t, err, "encryption should fail when payload exceeds 500 bytes")

386-419: Consider explicit error handling in test setup.

Lines 397 and 407 ignore errors from encryption functions. While the test would eventually fail on the assertions, explicit error handling with require.NoError would provide clearer failure messages if the setup itself fails.

Suggested improvement
 		// Create legacy encrypted message
-		legacyEncrypted, _ := PublicKeyEncryptJSON(legacyData, publicKey)
+		legacyEncrypted, err := PublicKeyEncryptJSON(legacyData, publicKey)
+		require.NoError(t, err, "legacy encryption setup should succeed")
 		legacyHash := base64.StdEncoding.EncodeToString(legacyEncrypted)

 		// Create new hybrid encrypted message
 		newOrder := &ent.PaymentOrder{
 			AccountIdentifier: "HYBRID456",
 			AccountName:       "Hybrid User",
 			Institution:       "Hybrid Bank",
 			Memo:              "Hybrid format",
 		}
-		hybridHash, _ := EncryptOrderRecipient(newOrder)
+		hybridHash, err := EncryptOrderRecipient(newOrder)
+		require.NoError(t, err, "hybrid encryption setup should succeed")

Note: This requires adding "github.com/stretchr/testify/require" to imports.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2dd603 and 04577e8.

📒 Files selected for processing (1)
  • utils/crypto/crypto_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
utils/crypto/crypto_test.go (1)
utils/crypto/crypto.go (3)
  • EncryptOrderRecipient (359-388)
  • GetOrderRecipientFromMessageHash (422-445)
  • PublicKeyEncryptJSON (156-170)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🔇 Additional comments (6)
utils/crypto/crypto_test.go (6)

3-11: LGTM!

The added imports are all utilized in the new test functions - base64 for message tampering tests, json for payload size calculations, strings for generating test data, and ent for the PaymentOrder type.


52-78: LGTM!

Solid round-trip test covering basic encryption and decryption with verification of all key fields.


80-105: LGTM!

Good coverage for the provider edge relationship, ensuring the ProviderID is correctly encrypted and recovered.


107-138: LGTM!

Good test for larger payloads with extensive metadata. The assertions verify complete round-trip integrity including metadata length.


222-320: LGTM!

Comprehensive coverage of edge cases:

  • Small metadata handling
  • Invalid base64 rejection
  • Tampered message detection (important for authenticated encryption)
  • Empty field handling
  • Nonce randomness verification (critical for cryptographic security)

323-361: LGTM!

Excellent backward compatibility test design. The legacy RSA format test correctly simulates the old integration pattern (without Nonce field) and verifies the fallback decryption mechanism works properly.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@sundayonah
Copy link
Collaborator

looks good

Copy link
Collaborator

@sundayonah sundayonah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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

Successfully merging this pull request may close these issues.

Implement hybrid encryption for message hash to support larger payloads

4 participants