GroupDocs.Signature for .NET supports verifying digital signatures embedded in raster images using steganography (LSB - Least Significant Bit technique). These signatures are invisibly embedded in image pixels and can be verified using the password that was used during signing.
Key Features
Password-Based Verification: Verify signatures using the password from signing
Detection Thresholds: Configurable detection threshold for verification (0-100%)
Full Data Extraction: Optional full data extraction mode for maximum accuracy
Format Support: Works with PNG and JPG image formats
Probability Detection: Get probability scores when using full extraction mode
How It Works
Digital signature verification in images:
Extraction: The embedded signature data is extracted from the least significant bits of image pixels
Password Verification: The extracted data is verified using the provided password
Threshold Check: The detection threshold determines if enough signature data was found
Result: Returns verification status and signature details
Requirements
Password Requirements
Must Match: Password must match the one used during signing
Case Sensitive: Yes, passwords are case-sensitive
Minimum Length: 4 characters (same as signing)
Supported Formats
✅ PNG - Fully supported
✅ JPG/JPEG - Fully supported
❌ BMP - Not supported for digital steganography signatures
Basic Usage
Verifying a Signed Image
usingGroupDocs.Signature;usingGroupDocs.Signature.Options;// Load the signed imageusing(Signaturesignature=newSignature("signed_image.png")){// Create verify options with the same password used for signingImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MySecurePassword123"};// Verify the signatureVerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine("Digital signature is valid!");Console.WriteLine($"Found {verifyResult.Succeeded.Count} verified signatures.");}else{Console.WriteLine("Digital signature is invalid or not found.");}}
Complete Verification Example
usingGroupDocs.Signature;usingGroupDocs.Signature.Options;stringsignedFile="signed_document.png";stringpassword="SecurePassword123";// Verify the signed imageusing(Signaturesignature=newSignature(signedFile)){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password=password};VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine("Digital signature is valid!");Console.WriteLine($"Verified signatures: {verifyResult.Succeeded.Count}");foreach(varsiginverifyResult.Succeeded){if(sigisDigitalSignaturedigitalSig){Console.WriteLine($" Signature ID: {digitalSig.SignatureId}");Console.WriteLine($" Sign Time: {digitalSig.SignTime}");Console.WriteLine($" Is Valid: {digitalSig.IsValid}");}}}else{Console.WriteLine("✗ Digital signature is invalid or not found.");if(verifyResult.Failed!=null&&verifyResult.Failed.Count>0){Console.WriteLine($" Failed verifications: {verifyResult.Failed.Count}");foreach(varfailureinverifyResult.Failed){Console.WriteLine($" - {failure}");}}}}
Advanced Usage
Custom Detection Threshold
The detection threshold determines the minimum percentage of signature data that must be detected for verification to succeed (0-100%). Default is 75%.
using(Signaturesignature=newSignature("signed_image.png")){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MySecurePassword123",DetectionThresholdPercent=90// Require 90% detection};VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine("Signature verified with 90% threshold");}else{Console.WriteLine("Signature verification failed - threshold not met");}}
Testing Different Thresholds
using(Signaturesignature=newSignature("signed_image.png")){stringpassword="MyPassword123";// Test different threshold valuesint[]thresholds={50,75,90,95,100};foreach(intthresholdinthresholds){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password=password,DetectionThresholdPercent=threshold};VerificationResultverifyResult=signature.Verify(verifyOptions);Console.WriteLine($"Threshold {threshold}%: {(verifyResult.IsValid ? "✓Valid" : "✗Invalid")}");}}
Full Data Extraction Mode
For maximum accuracy, you can enable full data extraction mode. This performs a more thorough analysis and provides a probability score.
using(Signaturesignature=newSignature("signed_image.png")){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MySecurePassword123",UseFullDataExtraction=true,// Enable full extractionDetectionThresholdPercent=85};VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine("Signature verified with full data extraction");// DetectedProbability is set when UseFullDataExtraction is trueif(verifyOptions.DetectedProbability.HasValue){Console.WriteLine($"Detection probability: {verifyOptions.DetectedProbability.Value}%");}}}
Working with Streams
You can verify images using streams instead of file paths:
usingSystem.IO;usingGroupDocs.Signature;usingGroupDocs.Signature.Options;// Verifying from streamusing(StreamimageStream=newFileStream("signed_image.png",FileMode.Open,FileAccess.Read))using(Signaturesignature=newSignature(imageStream)){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MySecurePassword123"};VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine("Signature is valid!");}}
Detection Threshold
The DetectionThresholdPercent property controls how strict the verification is:
Lower Threshold (0-50%): More lenient, may detect partial signatures
Default (75%): Balanced detection
Higher Threshold (90-100%): Very strict, requires nearly complete signature data
Choosing the Right Threshold
// For lenient verification (may detect partial signatures)ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword",DetectionThresholdPercent=50// Lower threshold};// For balanced verification (default)verifyOptions.DetectionThresholdPercent=75;// Default// For strict verification (requires complete signature)verifyOptions.DetectionThresholdPercent=95;// High threshold
Threshold Examples
using(Signaturesignature=newSignature("signed_image.png")){stringpassword="MyPassword123";// Test with different thresholdsvarthresholds=new[]{50,75,90,95,100};foreach(intthresholdinthresholds){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password=password,DetectionThresholdPercent=threshold};VerificationResultverifyResult=signature.Verify(verifyOptions);stringstatus=verifyResult.IsValid?"✓ Valid":"✗ Invalid";Console.WriteLine($"{threshold}% threshold: {status}");}}
Full Data Extraction
When UseFullDataExtraction is enabled:
Performs more thorough analysis using AnalyzePercentageDigitalSignature
Provides a probability score (0-100%) in DetectedProbability
More accurate but slightly slower
Useful when standard verification is uncertain
Using Full Data Extraction
using(Signaturesignature=newSignature("signed_image.png")){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword",UseFullDataExtraction=true,DetectionThresholdPercent=85};VerificationResultresult=signature.Verify(verifyOptions);if(result.IsValid&&verifyOptions.DetectedProbability.HasValue){Console.WriteLine($"✓ Signature detected with {verifyOptions.DetectedProbability.Value}% probability");}else{Console.WriteLine("✗ Signature not detected or below threshold");}}
When to Use Full Data Extraction
Use full data extraction when:
Standard verification gives uncertain results
You need maximum accuracy
Image may have been slightly modified
You want probability scores
// First try standard verificationImageDigitalVerifyOptionsstandardOptions=newImageDigitalVerifyOptions{Password="MyPassword"};VerificationResultstandardResult=signature.Verify(standardOptions);if(!standardResult.IsValid){// If standard verification fails, try full extractionImageDigitalVerifyOptionsfullExtractionOptions=newImageDigitalVerifyOptions{Password="MyPassword",UseFullDataExtraction=true,DetectionThresholdPercent=70// Lower threshold for full extraction};VerificationResultfullResult=signature.Verify(fullExtractionOptions);if(fullResult.IsValid){Console.WriteLine($"Signature found with {fullExtractionOptions.DetectedProbability}% probability");}}
Handling Verification Results
Detailed Result Processing
using(Signaturesignature=newSignature("signed_image.png")){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword123"};VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){Console.WriteLine($"✓ Signature valid. Found {verifyResult.Succeeded.Count} signature(s).");foreach(varsiginverifyResult.Succeeded){if(sigisDigitalSignaturedigitalSig){Console.WriteLine($" Signature ID: {digitalSig.SignatureId}");Console.WriteLine($" Sign Time: {digitalSig.SignTime}");Console.WriteLine($" Is Valid: {digitalSig.IsValid}");}}}else{Console.WriteLine("✗ Signature invalid or not found.");if(verifyResult.Failed!=null&&verifyResult.Failed.Count>0){Console.WriteLine($" Failed verifications: {verifyResult.Failed.Count}");foreach(varfailureinverifyResult.Failed){Console.WriteLine($" - {failure}");}}}}
Error Handling
Wrong Password
try{using(Signaturesignature=newSignature("signed_image.png")){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="WrongPassword"// Wrong password};VerificationResultverifyResult=signature.Verify(verifyOptions);if(!verifyResult.IsValid){Console.WriteLine("Signature verification failed - wrong password or no signature found.");}}}catch(Exceptionex){Console.WriteLine($"Error during verification: {ex.Message}");}
Password Validation
try{ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="123"// Too short, minimum is 4 characters};using(Signaturesignature=newSignature("signed_image.png")){VerificationResultverifyResult=signature.Verify(verifyOptions);}}catch(ArgumentExceptionex){Console.WriteLine($"Password validation error: {ex.Message}");// Output: "Password must be at least 4 characters long."}
Threshold Range Validation
try{ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword",DetectionThresholdPercent=150// Invalid: must be 0-100};using(Signaturesignature=newSignature("signed_image.png")){VerificationResultverifyResult=signature.Verify(verifyOptions);}}catch(ArgumentOutOfRangeExceptionex){Console.WriteLine($"Threshold error: {ex.Message}");// Output: "Detection threshold must be within 0-100 range."}
Best Practices
1. Use Appropriate Thresholds
// For critical applications, use higher thresholdImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password=password,DetectionThresholdPercent=95,// High threshold for critical verificationUseFullDataExtraction=true// Maximum accuracy};
2. Handle Verification Results Properly
VerificationResultverifyResult=signature.Verify(verifyOptions);if(verifyResult.IsValid){// Process successful verificationProcessValidSignature(verifyResult.Succeeded);}else{// Handle failed verificationHandleInvalidSignature(verifyResult.Failed);}
3. Try Full Extraction if Standard Verification Fails
// First attempt with standard verificationImageDigitalVerifyOptionsstandardOptions=newImageDigitalVerifyOptions{Password=password,DetectionThresholdPercent=75};VerificationResultresult=signature.Verify(standardOptions);if(!result.IsValid){// Try with full extraction and lower thresholdImageDigitalVerifyOptionsfullOptions=newImageDigitalVerifyOptions{Password=password,UseFullDataExtraction=true,DetectionThresholdPercent=60// Lower threshold};result=signature.Verify(fullOptions);}
4. Store Passwords Securely
// Retrieve password from secure storagestringpassword=GetPasswordFromSecureStorage();ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password=password};
5. Verify Original Signed Images
// Always verify the original signed image, not edited copiesstringoriginalSignedImage="signed_image.png";// OriginalstringeditedImage="edited_signed_image.png";// May have corrupted signature// Verify originalusing(Signaturesignature=newSignature(originalSignedImage)){ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword"};VerificationResultresult=signature.Verify(verifyOptions);// This should work}
// Always verify the original signed image, not edited copiesusing(Signaturesignature=newSignature("original_signed_image.png")){// Verify here}
Issue: Wrong Password Error
Solution: Ensure the password matches exactly (case-sensitive) the one used during signing.
// Password must match exactly (case-sensitive)ImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword123"// Must match signing password exactly};
Issue: BMP Format Not Working
Solution: BMP format does not support LSB steganography digital signatures. Use PNG or JPG format instead.
// Only PNG and JPG are supportedstring[]supportedFormats={".png",".jpg",".jpeg"};
Issue: Threshold Too High
Solution: Lower the detection threshold if verification fails.
// Start with lower thresholdImageDigitalVerifyOptionsverifyOptions=newImageDigitalVerifyOptions{Password="MyPassword",DetectionThresholdPercent=50// Lower threshold};// If that works, gradually increase to find optimal threshold
Summary
Verifying digital signatures in images provides:
✅ Password-Based Security: Verify using the signing password