[STUD-79136]: Configurable PGP key size, IResource inputs, paired-property normalization#562
Draft
alexandru-petre wants to merge 64 commits into
Draft
[STUD-79136]: Configurable PGP key size, IResource inputs, paired-property normalization#562alexandru-petre wants to merge 64 commits into
alexandru-petre wants to merge 64 commits into
Conversation
…URE, PITFALLS, SUMMARY) Synthesized findings from all four parallel research agents into unified SUMMARY.md. Includes executive summary, key findings by dimension, roadmap implications, confidence assessment, and open questions for phase planning. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eyPair - Create RsaKeySize enum with Rsa2048, Rsa3072, Rsa4096 members and [LocalizedDescription] attributes - Add KeySize InArgument<RsaKeySize> property to PgpGenerateKeyPair activity with [DefaultValue(RsaKeySize.Rsa4096)] - Place KeySize in Options category (IsPrincipal=false) after Overwrite property - Add KeySize DesignProperty to PgpGenerateKeyPairViewModel with dropdown widget - Add localization resource keys for enum values and property labels - Update Designer.cs files with generated resource accessors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion - Updated STATE.md with plan advancement (plan 1→2 complete, progress 50%) - Updated ROADMAP.md with phase 2 plan 1 progress - Marked requirements KEYGEN-01, DESIGN-01 as complete - Created 02-01-SUMMARY.md with full execution details Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…copy-paste-artifacts # Conflicts: # Activities/Credentials/UiPath.Credentials.Activities.ViewModels/Resources/ActivitiesMetadataWindows.json
…Metadata.json - Added KeySize property entry to PgpGenerateKeyPair activity metadata - Configured with Options category, DisplayNameKey and TooltipKey references - Positioned after Overwrite and before ContinueOnError properties - JSON validation passed
… entries - Added Activity_PgpGenerateKeyPair_Property_KeySize_Name = 'Key Size' - Added Activity_PgpGenerateKeyPair_Property_KeySize_Description - Added RsaKeySize_Rsa2048, RsaKeySize_Rsa3072, RsaKeySize_Rsa4096 enum member entries - Entries follow standard .resx XML format with xml:space='preserve' attribute
…tion and localization - Created 02-02-SUMMARY.md with task completion details and verification results - Advanced plan counter from 02 to 03 - Updated progress from 50% to 75% (3/4 plans complete) - Marked DESIGN-02 and DESIGN-03 requirements complete - Routed files to appropriate repositories via commit-to-subrepo
- Updated PackageReference in Directory.build.targets - Enables keySize parameter support in PgpCore GenerateKey() method Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…KeyPair() helper - Updated method signature to accept RsaKeySize keySize parameter with default Rsa4096 - Passes (int)keySize to pgp.GenerateKey() call - Added using statement for UiPath.Cryptography.Enums namespace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lper - Added keySizeValue read from KeySize property via this.KeySize.Get(context) - Updated CryptographyHelper.PgpGenerateKeyPair() call to pass keySizeValue parameter - Completes data flow from designer property to key generation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…256, AES-256) - Added using statement for Org.BouncyCastle.Bcpg - PgpEncryptStream: set HashAlgorithmTag.Sha256 and SymmetricKeyAlgorithmTag.Aes256 - PgpEncryptText: set HashAlgorithmTag.Sha256 and SymmetricKeyAlgorithmTag.Aes256 - Aligns encryption with RFC 9580 and 2025 enterprise security standards Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…256, AES-256) - PgpDecryptStream: set HashAlgorithmTag.Sha256 and SymmetricKeyAlgorithmTag.Aes256 - PgpDecryptText: set HashAlgorithmTag.Sha256 and SymmetricKeyAlgorithmTag.Aes256 - Ensures consistent enterprise-grade defaults across encrypt/decrypt pipeline - Aligns decryption with RFC 9580 and 2025 enterprise security standards Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added 02-03-SUMMARY.md documenting all 5 task completions - Updated STATE.md with phase progress (100% complete) - Marked requirements KEYGEN-02, AUDIT-01, AUDIT-02 as complete - Updated ROADMAP.md phase 02 status to Complete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…kward compatibility Phase 3 validates the KeySize implementation from Phase 2 through comprehensive parameterized testing: - Update PgpTestBase to accept optional keySize parameter (default Rsa4096) - Add [Theory] tests for all three key sizes (2048, 3072, 4096) - Add [Fact] backward compatibility test (activity without KeySize → 4096-bit default) - Add encrypt/decrypt roundtrip tests for all key sizes - Validate all five phase 3 requirements: KEYGEN-03, AUDIT-03, TEST-01, TEST-02, TEST-03 Plan is autonomous (3 tasks, no checkpoints), 1 wave. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…PgpTestBase - Add RsaKeySize import - Update constructor to accept optional keySize parameter with default RsaKeySize.Rsa4096 - Pass (int)keySize to pgp.GenerateKey() call - Maintains backward compatibility with existing test subclasses
…n PgpStandaloneTests - Add [Theory] test PgpGenerateKeyPair_WithKeySize_CreatesValidKey with [InlineData] for all three key sizes - Validates key generation with CryptographyHelper.PgpGenerateKeyPair(keySize parameter) - Add [Fact] test PgpGenerateKeyPair_Activity_WithoutKeySize_DefaultsTo4096 for backward compatibility - Verifies Activity defaults to Rsa4096 when KeySize property not set
…roundtrip tests in PgpTests - Add [Theory] test PgpEncryptDecryptText_WithGeneratedKeySize_Roundtrip with [InlineData] for all three key sizes - Generates keys at each size, encrypts plaintext with generated keys, decrypts and validates roundtrip - Validates TEST-03 and AUDIT-03: encrypt/decrypt operations work with all key sizes
…d backward compatibility - Created 03-SUMMARY.md with complete test coverage validation - Updated STATE.md to mark Phase 3 and entire project as complete - Updated ROADMAP.md with Phase 3 completion status and all requirements validated - All 12 requirements satisfied across all phases (100% coverage) - 5 test methods added: 1 PgpTestBase + 2 PgpStandaloneTests + 1 PgpTests - Parameterized testing validates all 3 RSA key sizes (2048, 3072, 4096) - Backward compatibility verified via Activity default behavior - Cross-size encrypt/decrypt validated for full interoperability
…IResource pattern verification
…tivity with dual input properties - Changed PgpSignFile base class from CodeActivity to AsyncTaskCodeActivity - Added InputFile property (IResource) with OverloadGroup(InputFilePath) - Added FileInputModeSwitch property to toggle between FilePath and File modes - Added PrivateKeyFile property (IResource) with OverloadGroup(PrivateKeyFilePath) - Added PrivateKeyFileInputModeSwitch property for independent key file mode switching - Replaced synchronous Execute method with async ExecuteAsync override - Implemented IResource resolution with await ResolveAsync() for both file inputs - Added explicit null/whitespace validation for resolved paths before helper call - Added required imports: System.Threading, System.Threading.Tasks, UiPath.Cryptography.Enums - ExecuteAsync resolves resources to strings before calling PgpFileSignHelper.ExecuteSign unchanged Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gnViewModelBase - Added four backup fields for preserving values during mode switching - Added InputFile and FileInputModeSwitch design properties - Added PrivateKeyFile and PrivateKeyFileInputModeSwitch design properties - Initialized all new properties in InitializeModel with correct IsPrincipal/IsVisible flags - Added two MenuActionsBuilder chains for independent file input mode switching - Backed up initial values in InitializeModel for toggle preservation - Added InitializeRules override to register both mode-switch action rules - Added ManualRegisterDependencies override to register dependencies for both mode switches - Implemented FileInputModeChanged_Action with backup/restore visibility toggle logic - Implemented PrivateKeyFileInputModeChanged_Action with independent toggle logic - Added required imports: System, System.Activities, UiPath.Cryptography.Enums Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nput mode properties - Added .resx entries for InputFile, FileInputModeSwitch, PrivateKeyFile, and PrivateKeyFileInputModeSwitch - Added corresponding Designer.cs property accessors for resource lookups - Fixed ExecuteAsync access modifier from protected internal to protected - All resource strings follow existing naming and description patterns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 2 tasks completed: PgpSignFile migration to AsyncTaskCodeActivity, PgpSignViewModelBase enhancement - All file inputs (InputFilePath/InputFile, PrivateKeyFilePath/PrivateKeyFile) support dual input modes - Independent mode switches allow flexible designer experience - Backup/restore pattern preserves user values across mode toggles - MenuActionsBuilder integration creates intuitive mode-switching UI - Build succeeds with Release configuration - Next: Plan 04-02 for metadata registration and validator support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vity with dual input properties
…ify dual input mode properties
… for PgpVerify - Added InputFile property with DisplayName and Tooltip keys - Added FileInputModeSwitch property for mode toggling - Added PublicKeyFile property with DisplayName and Tooltip keys - Added PublicKeyFileInputModeSwitch property for independent key file mode switching - All properties marked with IsVisible=false and proper Category assignment - Metadata structure matches pattern from PgpSignFile and PgpClearSignFile Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…nput mode Plan 04-04 complete: - Registered InputFile, FileInputModeSwitch, PublicKeyFile, PublicKeyFileInputModeSwitch in ActivitiesMetadata.json - Verified all 8 localization entries present in Resources.resx from plan 04-03 - Build succeeded with no errors - All three PGP file-based activities now have complete dual-input mode support Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Advanced plan counter to 04-04 (4 of 5) - Updated progress to 90% (9 of 10 plans completed) - Updated ROADMAP.md with plan 04-04 SUMMARY.md completion Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…ties - Fixed existing test bugs: extract result from WorkflowInvoker dictionary - Added reflection-based tests to verify IResource properties exist - Verified all three PGP activities (PgpSignFile, PgpClearSignFile, PgpVerify) have: - InputFile/PublicKeyFile IResource properties - FileInputModeSwitch and file-specific mode switches - Proper OverloadGroup attributes - Documented OverloadGroup validation limitation preventing mixed-mode testing - Test suite now has 16 passing tests (up from baseline) Deferred: Full IResource roundtrip testing via WorkflowInvoker requires fixing activity OverloadGroup validation design (out of scope for this plan).
…tion Verification found that PgpClearSignFile has dual input mode properties defined but still uses synchronous CodeActivity base class. ExecuteAsync method never implemented; IResource inputs (InputFile, PrivateKeyFile) are silently ignored at runtime. Plan 04-06 closes this gap by migrating PgpClearSignFile to AsyncTaskCodeActivity with ExecuteAsync and proper IResource resolution using the proven PgpSignFile reference pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Resource resolution - Changed base class from CodeActivity to AsyncTaskCodeActivity - Added System.Threading and System.Threading.Tasks imports - Replaced Execute() with async ExecuteAsync(AsyncCodeActivityContext, CancellationToken) - Implemented IResource resolution for both InputFile and PrivateKeyFile - Both files resolved via await ResolveAsync() pattern matching PgpSignFile reference - Validated resolved paths before passing to PgpFileSignHelper.ExecuteSign() - Preserved exception handling and telemetry patterns - Code compiles without errors - Closes verification gap: FileInputModeSwitch and PrivateKeyFileInputModeSwitch now functional at runtime
…n plan - Migrated PgpClearSignFile from CodeActivity to AsyncTaskCodeActivity - Implemented async ExecuteAsync() with IResource resolution for InputFile and PrivateKeyFile - Both files now properly resolved via await ResolveAsync() pattern - Matches PgpSignFile reference implementation exactly - Closes verification gap: FileInputModeSwitch and PrivateKeyFileInputModeSwitch now functional - Phase 04 objective 100% achieved: all file-based activities support dual input mode
- Archive ROADMAP and REQUIREMENTS to .planning/milestones/v1.0-* - Add MILESTONES.md index with v1.0 entry - Collapse ROADMAP.md to milestone summary - Update PROJECT.md to current-state format - Reset STATE.md to milestone-complete Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Archived to .planning/milestones/v1.0-REQUIREMENTS.md. Next milestone will create a fresh REQUIREMENTS.md via /gsd-new-milestone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ChaCha20-Poly1305 as a new EncryptionAlgorithm alongside AES-GCM. Refactors AES-GCM into shared AEAD helpers (EncryptAead/DecryptAead) so both ciphers share PBKDF2 key derivation and wire format (salt|iv|cipher|tag). Marks TripleDES [Obsolete] as it is no longer considered safe. ChaCha20-Poly1305 is flagged as not FIPS-compliant.
…ssphrase for PgpGenerateKeyPair Adds a KeySize property (RsaKeySize enum, default 4096) so users can choose 2048/3072/4096 instead of being locked to the previous hardcoded value. Also adds a PassphraseSecureString input alongside the existing string Passphrase, with a paired PassphraseInputModeSwitch (marked Obsolete; the design-time menu action drives the toggle) and CacheMetadata validation that the active input is set. Moves ContinueOnError to the Options category to match other activities.
…ategory cleanup across activities Adds InArgument<IResource>/InArgument<ILocalResource> properties for key and file inputs across Encrypt/Decrypt File/Text and PGP activities so users can point at Orchestrator storage buckets instead of plain file paths; resolution is done lazily via ToLocalResource().ResolveAsync(). Marks the legacy *InputModeSwitch properties [Obsolete] (the design-time Main menu actions now drive these toggles) and adds matching CS0618 pragmas in tests that still exercise the legacy flags. Moves ContinueOnError from the Common category to Options across all affected activities for consistency. Updates ActivitiesMetadata.json, resx strings, and Designer.cs to register the new properties and localized labels. Also pulls in the new Shift-JIS encoding test and ChaCha20-Poly1305 round-trip/cross-cipher tests, and adopts the new UiPath.Shared.ViewModels.Tests shared project (with ActivityMetadataTests and a MetadataChecker harness) registered in the solution files.
…crypt + document wire format (STUD-64429) Customer report STUD-64429: TripleDES (and by extension every other non-AEAD symmetric algorithm in this package) produces ciphertext that no external tool can decrypt, and rejects ciphertext from external tools, because the UiPath wire format Base64(salt | IV | ciphertext) with PBKDF2-derived keys is undocumented and the decrypt failure surfaces as a generic CryptographicException. This change closes the documentation + diagnostic gap without altering the encryption pipeline. CryptographyHelper.DecryptData now: - Rejects inputs shorter than salt + IV with a localized message that names the expected wire format and minimum byte count. - Catches the inner CryptographicException raised by CryptoStream when PKCS7 padding fails on a wrong-format / wrong-key input, and rethrows it with a hint pointing at the wire-format spec and likely causes (different tool / wrong key / wrong encoding). Adds a docs/symmetric-wire-format.md reference covering the exact byte layout per algorithm, PBKDF2 parameters, and copy-paste Python encoder and decoder snippets for both non-AEAD and AEAD ciphers. Appends a short wire-format note to the Algorithm description on EncryptText, DecryptText, EncryptFile, DecryptFile. Adds four tests covering: the salt-randomization contract across TripleDES / AES / DES, activity-level non-determinism on repeat encryption, the new too-short diagnostic, and the new wrapped padding diagnostic with InnerException preserved. 500/500 existing tests continue to pass.
…rId, align with OpenPGP convention
PgpGenerateKeyPair previously exposed the OpenPGP User ID as a property
called Username with the description "username (or email) to associate
with the generated key pair". This undersells what the field is: the
OpenPGP User ID packet (RFC 4880 / RFC 9580 §5.11) embedded in the
generated public key, conventionally an RFC 2822 mailbox like
"Name <email@example.com>".
Renames the C# property and the resx keys from Username to UserId. The
displayed label becomes "User ID", the description points users at the
mailbox form with an example, and the input shows a placeholder hint
("Your Name <your.email@example.com>") via EditPlaceholder. Description
also names the public key specifically — the User ID is what others see
when importing it.
Reorders the design-time layout so each field sits with the key it
belongs to:
PublicKeyFilePath → UserId → PrivateKeyFilePath → Passphrase
This pairs UserId with the public key (where the User ID packet lives)
and keeps Passphrase adjacent to PrivateKeyFilePath (matching every
other PGP activity in the package).
Property rename is safe because PgpGenerateKeyPair has not yet been
publicly released with this property — no XAML in customer workflows
binds the old Username name.
Localized resx files keep the old _Username_* keys with their old
translations; the resource manager falls back to English on the new
_UserId_* keys until a translation pass picks them up. Same pattern as
the recent storage-resource commit.
500/500 existing tests continue to pass.
…PGP-passphrase-bearing activities Mirrors the PgpGenerateKeyPair pattern (commit b4c4c86) across the six activities that consume a PGP passphrase: - EncryptText, DecryptText, EncryptFile, DecryptFile (when Algorithm == PGP) - PgpSignFile, PgpClearSignFile (unconditional) Each activity now exposes Passphrase as InArgument<string> alongside a new PassphraseSecureString as InArgument<SecureString>, with a hidden PassphraseInputModeSwitch (KeyInputMode, [Browsable(false)] + [Obsolete]) that the design-time Main-menu toggle drives. The previous InArgument<SecureString> Passphrase contract is renamed to PassphraseSecureString and Passphrase becomes the new string-typed property — confirmed acceptable because this typing had not been publicly released. CacheMetadata validates whichever side is null based on the active mode (gated on Algorithm == PGP for the four symmetric activities and on SignData == true for the encrypt-side variants). Execute() reads the active side, throws ArgumentNullException with the matching resource key, and collapses SecureString to string via NetworkCredential before calling the helpers. PgpStreamHelper and PgpFileSignHelper signatures were updated to take a plain string passphrase since the activity now performs the conversion (drops System.Net / System.Security imports from both helpers). ViewModel bases (EncryptCryptoViewModelBase, DecryptCryptoViewModelBase, PgpSignViewModelBase) gained ConfigurePassphraseInputModeMenuActions, SwitchToPassphrase / SwitchToPassphraseSecureString task handlers, and persistence fields. EncryptCrypto and DecryptCrypto bases route final visibility through a shared ApplyPassphraseVisibility() that combines Algorithm == PGP (and SignData on the encrypt side) with the active mode flag. Concrete viewmodels call ConfigurePassphraseInputModeMenuActions() in InitializeModel. Resx adds three keys per activity (PassphraseSecureString Name/Description and PassphraseInputModeSwitch Name/Description, with the existing Passphrase Name/Description re-described for the plain-string variant). Designer.cs got 24 matching accessors. Localized resx files left alone — new keys fall back to English. ActivitiesMetadata.json adds a PassphraseSecureString block per activity mirroring the existing Passphrase block's flags. The [Browsable(false)] PassphraseInputModeSwitch follows package convention and is not added to metadata. Tests in PgpTests.cs migrate the two existing "new InArgument<SecureString>" passphrase usages to "new InArgument<string>(Passphrase)" (using the PgpTestBase const), and a new test PgpDecryptText_WithSecureStringPassphrase_RoundTrips exercises the SecureString branch end-to-end. Docs (6 .md files) gain a PassphraseSecureString row alongside the updated Passphrase row, with a note about the Main-menu toggle. 521 of 521 tests pass (500 baseline + 21 newer additions including the new SecureString round-trip).
…ry in Encrypt/DecryptFile
Before: setting OutputFileName on EncryptFile or DecryptFile while
leaving OutputFilePath empty produced an empty filePath in
FilePathHelpers.GetDefaultFileNameAndLocation. That empty string flowed
through to CryptographyLocalItem's constructor and File.WriteAllBytes("")
threw ArgumentException("Empty path name is not legal"). The intent of
OutputFileName-only — "rename the output, keep the directory" — was
silently unreachable.
After: when OutputFileName is provided and OutputFilePath is empty, the
helper now builds filePath by combining the input file's directory with
the given OutputFileName, and applies the same File.Exists / Overwrite
guard the all-defaults branch already does. Activities that supplied
both OutputFilePath and OutputFileName, or only OutputFilePath, are
unaffected.
Adds a regression test EncryptFile_WithOnlyOutputFileName_WritesToInputDirectoryWithThatName
that asserts the produced output is at <input-dir>/<custom-name> and
non-empty. The earlier 521 tests continue to pass; total now 522.
…ocument OutputFilePath fallback - Sentence case for output display names: `Encrypted File`/`Decrypted File`/`Encrypted Text`/`Decrypted Text` -> `Encrypted file`/etc. - `OutputFilePath` description on EncryptFile/DecryptFile now mentions the `<input-name>_Encrypted<ext>` / `_Decrypted<ext>` fallback when the field is left empty. English resx only; the 12 locale resx files continue to fall back to English (same pattern as other recent additions on this branch).
…ta on PgpSign/ClearSign/Verify activities `PgpSignFile`, `PgpClearSignFile`, and `PgpVerify` each declared two distinct `[OverloadGroup]`s for their path/resource pairs (e.g. `InputFilePath` and `PrivateKeyFilePath`). Per WF semantics, distinct groups model *alternative* configurations and only one may be configured at a time -- so any valid customer XAML that set both the input file and the key file triggered: "The following overload groups are configured: InputFilePath, PrivateKeyFilePath. Only one overload group should have its arguments configured." The path/resource pairs are independent inputs (both required), not alternatives, so OverloadGroup is the wrong tool. Removed `[OverloadGroup]` and `[RequiredArgument]` from the four file properties on each activity, and replaced them with a `CacheMetadata` override that validates each pair against its `*InputModeSwitch` (and `Mode` on `PgpVerify`). Closes open item #4 from the session-state notes -- the async PGP-sign activities now have design-time validation that matches the symmetric activities' behavior. Tests: - Added six regression tests covering string-path config and sign/verify round-trips for all three activities. - Added `PgpFullPipeline_Activities_EndToEnd_Works` end-to-end test mirroring a customer-reported workflow (generate -> sign -> clear-sign -> verify signature / clear-signature / public-key). - Removed the previously disabled-stub comments that were blocked on this bug.
…ecryptFile sign+verify round-trips The existing PGP file/text tests skipped `SignData=true` / `VerifySignature=true`. Added two round-trip tests that mirror customer workflows passing both public + private keys plus the passphrase through Encrypt/DecryptText and Encrypt/DecryptFile.
…PgpSign/ClearSign/Verify Direct invocations of `ActivityValidationServices.Validate` prove the new `CacheMetadata` overrides actually run at design-time validation (not just at runtime via `WorkflowInvoker.Invoke`), and that `PgpVerify` in `Mode=PublicKey` correctly does not require the signed-file input while still requiring the public key.
…l activities Every paired property (path string ↔ IResource, plain string ↔ SecureString) now follows the same pattern that EncryptText.PublicKeyFilePath ↔ PublicKeyFile already used: no dedicated `*InputModeSwitch` enum, viewmodel uses pure `HasValue`-inference for initial mode, and runtime resolves via string-first fallback. Switch enums disposition (per origin/masters/Cryptography baseline): - Kept as [Obsolete][Browsable(false)] (still on masters, preserves XAML back-compat): `KeyInputModeSwitch` on Encrypt/Decrypt/Hash and `FileInputModeSwitch` on Encrypt/Decrypt. Still declared but no longer read by viewmodel or runtime. - Deleted (only added on this branch): every `PassphraseInputModeSwitch`, every `*InputModeSwitch` on the PGP activities, and `FileInputModeSwitch` on KeyedHashFile. Runtime fallback shape: - File pairs: try the string `*FilePath` first; if empty, resolve the `*File` IResource to a local path. Throws ArgumentNullException if both are empty. - Key/passphrase pairs: try the plain `Key`/`Passphrase` string first; fall back to the SecureString side; throws if both empty. Extracted `Helpers/PgpFileResolver.cs` to consolidate the path-resolution and passphrase-resolution helpers used by PgpSignFile / PgpClearSignFile / PgpVerify. Renamed `PgpGenerateKeyPair` → `PgpGenerateKeys` (class, viewmodel, helper method, resx keys, metadata, docs file) to match the display name "PGP Generate Keys". Unpublished activity, so no back-compat shim. The other three PGP activities (`PgpSignFile`, `PgpClearSignFile`, `PgpVerify`) already matched their display names. Tests: - Dropped the design-time `*_CacheMetadata_*` tests for PGP activities — runtime fallback is the source of truth now, no design-time validation for these pairs. - Renamed `*_FilePathMode_*_ThrowsAtRuntime` to `*_Empty*_Throws` since the switch is gone; behavior identical. - Trimmed `*_Has_IResource_Properties` reflection tests to the two pair sides (no more switch property to check). - All 9 tests that previously set `*InputModeSwitch` properties drop those lines for deleted switches; kept-obsolete ones still build fine because the property still exists. Net: 518 / 518 tests passing.
Matches the spelling used by GnuPG (`--clearsign` / `--clear-sign`) and the OpenPGP RFC 9580 ("cleartext signature"). Unpublished activity, so no back-compat shim. The other PGP activities (`PgpSignFile`, `PgpVerify`, `PgpGenerateKeys`) already match their display names.
Renamed surfaces:
- Activity class, viewmodel class, files, resource keys, ActivitiesMetadata.json entries, docs file.
- Display name "PGP Clear Sign File" → "PGP Clearsign File".
- PgpVerify Mode dropdown label "Clear-Signed File (Text)" → "Clearsigned File (Text)" (and matching tooltips).
- Output property display "Clear-Signed File" → "Clearsigned File".
- Misc display strings ("clear signing" → "clearsigning", "clear-signature" → "clearsignature").
Not renamed (internal identifiers, kept for code stability):
- `CryptographyHelper.PgpClearSign(...)` helper method.
- `PgpVerifyMode.ClearSignature` enum value.
- `ClearSignedFile` output property name on `PgpClearsignFile`.
- Private `_ClearSigned` filename suffix.
PGP runs through PgpCore + BouncyCastle (the open-source edition, not BC-FIPS), which is not a CMVP-validated cryptographic module. The algorithms we configure (RSA, SHA-256, AES-256) are FIPS-approved choices, but FIPS 140 validates the module, not the algorithm — so this code path is not FIPS-compliant. No behavior change in the Encrypt/Decrypt activities: their CacheMetadata short-circuits the IsFipsCompliant check when `Algorithm == PGP` before it reaches this branch. The correction is for any future caller that might query this directly.
…ackageIconUrl Silences NU5125 and NU5048 warnings emitted by NuGet on every Cryptography packaging build. - `<PackageLicenseUrl>` (deprecated) → `<PackageLicenseFile>LICENSE.md</PackageLicenseFile>` pointing at the existing license file two directories up; added `<None Include="..\LICENSE.md" Pack="true" PackagePath="" />` so it ships in the .nupkg. - The old docs URL that was misused as a license URL moves to `<PackageProjectUrl>` where a docs link belongs. - `<PackageIconUrl>` (deprecated) removed; no local icon file exists to feed `<PackageIcon>`, and modern NuGet was silently ignoring the URL anyway.
…and design-time warning
Follows up on `85a6006` (which corrected `IsFipsCompliant(PGP)` to return `false`) to make the non-FIPS classification visible in Studio:
- Algorithm dropdown label `PGP` reworded from `PGP (Pretty Good Privacy)` → `PGP - Pretty Good Privacy (Non-FIPS)`. The `(Non-FIPS)` suffix matches the convention used by `ChaCha20-Poly1305 (Non-FIPS)`, `RC2 (Non-FIPS)`, `Rijndael (Non-FIPS)`; the hyphen replaces the redundant inner parens.
- `CacheMetadata` in EncryptFile / DecryptFile / EncryptText / DecryptText: dropped the `Algorithm != EncryptionAlgorithm.PGP &&` short-circuit before the FIPS check. The check now honors `IsFipsCompliant` uniformly, so selecting PGP surfaces the same yellow `FipsComplianceWarning` as RC2 / Rijndael / ChaCha20-Poly1305 do.
The existing warning text ("The selected algorithm does not have a FIPS compliant implementation. This might not work on some machines.") applies equally to the PgpCore + BouncyCastle path — no string changes needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem Statement
The Cryptography pack accumulated several pain points since the v2.0 release:
IResource) inputs — file activities only accepted local string paths.[OverloadGroup]on the existing PGP sign / clear-sign / verify activities was misused (validator rejected any XAML that bound both file + key inputs).IsFipsCompliant, even though the underlying PgpCore + BouncyCastle path is not a CMVP-validated module. The dropdown label and design-time warning didn't surface this either.Analysis
The work splits into a few intertwined themes across the 39 Cryptography-scoped commits on this branch. The PGP signing primitives themselves (Sign / Clearsign / Verify / GenerateKey) were already on develop via PR #514; this PR makes them production-ready and unifies the pack:
RsaKeySizeenum (2048 / 3072 / 4096) defaulting to 4096; SHA-256 hashing; AES-256 session keys; renamedPgpGenerateKeyPair.Username → UserIdto match OpenPGP convention.EncryptionAlgorithmis AESGCM.docs/symmetric-wire-format.md) and emit a localized hint pointing at the spec when foreign-format ciphertext fails to decrypt.IResourceproperties on every file activity (Encrypt / Decrypt / Hash / Pgp*) with viewmodel menu-action toggles and runtime resolution.OverloadGroupfix on PGP sign / clear-sign / verify — distinct[OverloadGroup]names made the file + key pairs mutually exclusive at the validator level, which broke every valid XAML. Replaced with runtime fallback resolution.*InputModeSwitchenum, viewmodel uses pureHasValue-inference for initial mode, runtime resolves via string-first fallback. Kept obsolete switches that existed onorigin/masters/Cryptographyfor XAML deserialization compatibility; deleted switches that were only ever added since the last release.PgpGenerateKeyPair → PgpGenerateKeys(matches display "PGP Generate Keys"),PgpClearSignFile → PgpClearsignFile(matches GnuPG--clearsignspelling and RFC 9580 "cleartext signature").PgpSignFileandPgpVerifyalready matched.IsFipsCompliant(PGP)now returnsfalse(PgpCore + open-source BouncyCastle is not a CMVP-validated module). The dropdown label changedPGP (Pretty Good Privacy)→PGP - Pretty Good Privacy (Non-FIPS)to match how other non-FIPS ciphers are labeled, and the existing yellow design-timeFipsComplianceWarningnow also surfaces when PGP is selected (theAlgorithm != PGP &&short-circuit was removed from the four CacheMetadata methods).<PackageLicenseUrl>/<PackageIconUrl>in favor of<PackageLicenseFile>(the existingLICENSE.mdnow ships in the .nupkg) and<PackageProjectUrl>.Considered Use Cases
KeySizedefaults to 4096.CryptographicException.Implementation
New files (4 truly new + 3 renamed-with-rewrite):
UiPath.Cryptography/Enums/RsaKeySize.cs— 2048 / 3072 / 4096.UiPath.Cryptography.Activities/Helpers/PgpFileResolver.cs— shared string-first fallback for path ↔ IResource and string ↔ SecureString.Activities/Cryptography/docs/symmetric-wire-format.md— STUD-64429 spec.UiPath.Cryptography.Activities.Tests/Resources/ActivityMetadataTests.cs— metadata invariant checks.PgpGenerateKeys.cs(renamed + rewritten fromPgpGenerateKeyPair.cs),PgpClearsignFile.cs(renamed + rewritten fromPgpClearSignFile.cs), and the matching viewmodels.Modified (~57 files):
IsFipsCompliantcheck (no PGP short-circuit).HasValue-inference for initial mode, switch handlers null the inactive side, no writes to obsolete*InputModeSwitchenums.CryptographyHelper.cs— added AESGCM / ChaCha20-Poly1305; documented obsolete-cipher rationale; correctedIsFipsCompliant(PGP)to returnfalse.UiPath.Cryptography.resx—PGPlabel gets the(Non-FIPS)suffix, parens around the long form replaced with a hyphen for legibility.ActivitiesMetadata.json, English.resx,Designer.csaccessors — kept in lock-step with class / property renames and switch deletions.Removed: deprecated
<PackageLicenseUrl>/<PackageIconUrl>in the Packaging csproj.Caveats / Potential Issues
IsFipsCompliant(PGP)semantics flipped fromtruetofalse. This now produces an observable yellow design-time warning when the algorithm is selected — that's the intended behavior, but it is a new warning that didn't appear in v2.0 for workflows that had been authored against PGP..resxfiles are intentionally stale for new keys added on this branch (Passphrase / Passphrase Secure, IResource displays, UserId, normalized pair entries). The resource manager falls back to English for missing keys. A translation pass is a follow-up.KeyInputModeSwitchon Encrypt / Decrypt / Hash,FileInputModeSwitchon Encrypt / Decrypt) are still declared on the activity class for XAML back-compat with already-published workflows. They're[Browsable(false)] [Obsolete]and never read by the viewmodel or runtime — deserialization is by construction (property exists on the class), not verified by a load-an-XAML test.OutputFileName+OutputFilePathboth set: pre-existing behavior preserved (FileName silently ignored when FilePath is also set). Documented as an open item; no reported customer impact.How to Test
dotnet build Activities/Activities.Cryptography.sln— expect 0 errors and 1 pre-existing unrelated CS1998 warning (CryptographyLocalItem.cs:73). NU5125 / NU5048 should be gone.dotnet test Activities/Activities.Cryptography.sln— expect 518 / 518 passing.dotnet test --filter "FullyQualifiedName~RoundTrip|FullyQualifiedName~EndToEnd"— 12 passing (covers the three customer XAMLs reported during development).PGPandGenerate Keys— both should surface the activity (renames make the class names match the display names).PGP - Pretty Good Privacy (Non-FIPS)should be visible. Select it: the yellowFipsComplianceWarningshould appear in the designer next to the activity.