I am using a smart card that is signing a SHA-1 hash of a document, and compute a 256 bytes digital signature.
I am using the code posted on this question - iText signing PDF using external signature with smart card.
My problem is that I get the error:" The document has been altered or corrupted since the signature was applied".
I am using a GUI to create the hash and then send the signed 256 bytes that is computed on the card to the signing functions .
Here is my code:
hash creating code of filepath pdf document:
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash= sha1.ComputeHash(pdfBytes);
the above code is used in one of the GUI functions to create the hash of the document
namespace EIDSmartCardSign
{
class PdfSignature
{
private string outputPdfPath;
private string certPath;
byte[] messageDigest;
private string inputPdfPath;
public PdfSignature(byte[] messageDigest, string inputPdfPath,string outputPdfPath)
{
this.messageDigest = messageDigest;
this.outputPdfPath = outputPdfPath;
this.inputPdfPath = inputPdfPath;
}
public void setCertPath(string certPath)
{
this.certPath = certPath;
}
public void signPdf()
{
X509Certificate2 cert = new X509Certificate2();
cert.Import(certPath); // .cer file certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1] ;
chain[0] = certParse.ReadCertificate(cert.RawData);
X509Certificate2[] certs;
PdfReader reader = new PdfReader(inputPdfPath);
FileStream fout = new FileStream(outputPdfPath,FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, fout, '\0',null,true);
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SignatureCreator = "Me";
appearance.Reason = "Testing iText";
appearance.Location = "On my Laptop";
iTextSharp.text.Rectangle rec = new iTextSharp.text.Rectangle(50, 50, 250, 100);
appearance.SetVisibleSignature(rec, 1, "Signature");
IExternalSignature extSignature= new MyExternalSignature("SHA-1",this.messageDigest);
MakeSignature.SignDetached(appearance, extSignature, chain, null, null, null, 0, CryptoStandard.CMS);
//MakeSignature.
}
}
}
Your hash creating function
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash = sha1.ComputeHash(pdfBytes);
calculates the wrong hash value.
Have a look at this answer on Information Security Stack Exchange, in particular the sketch
shows that to get the document bytes to sign you do not take the original PDF but instead have to prepare it for integrating the signature container (add signature field, field value with some space reserved for the signature container, and field visualization) and then hash all the bytes except the space reserved for the signature container.
Furthermore, even this naked hash is not the data to sign. Instead a set of attributes is built, one of them containing the document hash calculated as above, other ones containing references to the signer certificate etc., and these attributes are to be signed.
Thus, instead do what you already claimed to be doing:
I am using the code posted on this question - iText signing PDF using external signature with smart card.
In particular the code there does not sign the hash of the whole file but instead uses the data the method Sign of the IExternalSignature implementation receives as parameter which is constructed as explained above.
More details
In a comment the OP said
The card I am working with expects a 20 bytes hash.
20 bytes would be typical for a naked hash generated by either SHA1 or RIPEMD-160. According to your question text, I assume the former algorithm is used. (This by the way indicates that the context does not require a high security level as SHA1 effectively is already phased out or in the process of being phased out for such use cases.)
What steps are needed to further create this hash After hashing the contents of the pdf?
Simply do as in the IExternalSignature implementation in the question you referenced:
public virtual byte[] Sign(byte[] message) {
byte[] hash = null;
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
hash = sha1.ComputeHash(message);
}
byte[] sig = MySC.GetSignature(hash);
return sig;
}
(Obviously chances are that your smart card signing routine is not called MySC.GetSignature and you have to replace that call accordingly...)
As your card appears to expect a naked hash value in contrast to the card of the OP of the referenced question, this should work for you.
Where can I find examples of creating the aformentioned integrated signature container?
In the examples to the iText white paper Digital Signatures for PDF Documents.
After the signature process, I have 256 bytes signed data, 3 .cer certificates exported from the card.
256 bytes signed data sounds like a naked signature generated using RSA or RSASSA-PSS with a 2048 bit key size.
That been said, you need the signer certificate before signing: In most relevant profiles the signed attributes have to contain a reference to the signer certificate. In the code in the question you referenced that signer certificate is handled here
public void StartTest(){
X509Certificate2 cert = new X509Certificate2();
cert.Import("cert.cer"); // certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { certParse.ReadCertificate(cert.RawData) };
[...]
MyMakeSignature.SignDetached(appearance, externalSignature, chain, null, null, tsc, 0, CryptoStandard.CADES);
In particular you have to identify the correct signer certificate among those three certificate your card returns; otherwise you might have the same issue as the OP in the referenced question.
How do I create the Contents object when I have all of this data?
Considering what you said about your use case, chances are good that you really merely have to use the code posted of the question iText signing PDF using external signature with smart card with minor adaptions.
Related
I have a small application running on an ESP32 dev board (I use the Arduino IDE together with the shipped mbedtls) that issues and verifies JWT tokens. I have at first used RSA signatures successfully, but now wanted to go for shorter signatures and thus attempted to use ECDSA.
The application itself can issue tokens and verify them as well, but if I attempt to verify the tokens outside of my application - for instance with JOSE or the Debugger- I get verification failures and I cant quite wrap my head around why this is happening.
This is an example token (this token does practically not contain information):
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzI0MTMxNjgsImV4cCI6MTY3MjQxNjc2OH0.MEUCIAjwEDXI424qjrAkSzZ_ydcVLOSAvfQ8YVddYvzDzMvQAiEAkVy4d-hZ01KpcMNKhPHk8E_SDYiB4JKwhm-Kc-Z81rI
This is the corresponding public key (this key is not used anywhere besides the purpose of presenting the issue here):
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUGnNIOhPhZZSOg4A4BqAFtGO13W4BGDQpQ0ieTvLU9/CXrY7W77o7pNx7tvugeIoYJxS0NjmxvT4TMpo4Z8P7A==
-----END PUBLIC KEY-----
As far as I understand, JWT tokens can be issued and verified using ECDSA. The so called "ES256" method is supposed to use prime256v1 in combination with SHA256, so I generated my key material with the following commands:
openssl ecparam -name prime256v1 -genkey -noout -out ecc-private.pem
openssl ec -in ecc-private.pem -pubout -out ecc-public.pem
For the signing part, the private key is loaded as follows, where ecc_priv is a String containing the PEM representation of the key:
//get the key
byte *keybuffer = (byte*)malloc((ecc_priv.length()+1)*sizeof(byte));
ecc_priv.getBytes(keybuffer, ecc_priv.length() + 1);
mbedtls_pk_context pk_context;
mbedtls_pk_init(&pk_context);
int rc = mbedtls_pk_parse_key(&pk_context, keybuffer, ecc_priv.length() + 1, NULL, 0);
if (rc != 0){
printf("Failed to mbedtls_pk_parse_key: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
free(keybuffer);
Since this worked for me with RSA keys, I just replaced the keys and kept all other code to sign the actual message. As far as I understand, this should be possible with mbedtls_pk methods:
//mbedtls context
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
const char* pers="some entropy";
mbedtls_ctr_drbg_seed(
&ctr_drbg,
mbedtls_entropy_func,
&entropy,
(const unsigned char*)pers,
strlen(pers));
//get the header and payload bytes
byte *headerAndPayloadbytes = (byte*)malloc((headerAndPayload.length()+1)*sizeof(byte));
headerAndPayload.getBytes(headerAndPayloadbytes, headerAndPayload.length() + 1);
//prepare digest
uint8_t digest[32];
rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), headerAndPayloadbytes, headerAndPayload.length(), digest);
if (rc != 0) {
printf("Failed to mbedtls_md: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
free(headerAndPayloadbytes);
//prepare output
byte *oBuf = (byte*)malloc(5000*sizeof(byte));
size_t retSize;
//sign digest
rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), oBuf, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg);
if (rc != 0) {
printf("Failed to mbedtls_pk_sign: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
//encode signature to base64
unsigned int osize = encode_base64_length(retSize);
byte *output = (byte*)malloc((osize+1)*sizeof(byte));
encode_base64(oBuf, retSize, output);
String sig = String((char*)output);
free(output);
//base64 URL specific
sig.replace('+','-');
sig.replace('/','_');
sig.replace("=","");
String completejwt = headerAndPayload + "." + sig;
//free resources
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
mbedtls_pk_free(&pk_context);
free(oBuf);
My expectation was that I can simply replace the RSA keys with the ECDSA (prime256v1) keys and keep everything else as is, but the resulting token are not verifiable outside of my application. Again I want to emphasize that inside my application I can definitely verify the token and that the code worked perfectly fine with RSA keys, even outside my application. There must be something Im missing here, Im sure about that.
Any help or directions to research are highly appreciated.
EDIT: Here is a minimal compilable example (Arduino sketch)
Your ECDSA signature is a DER-encoded ASN.1 structure, rather than a simple r || s concatenation as proposed by IEEE-P1363 which is what the JOSE specification mandates.
I'm trying to sign a pdf using PCKS11 (USB Token) and iText, It works fine when I use SHA-1 algorithm, the signature is valid and everything works fine however when I change it to SHA256 the signature is not valid, Does anyone know why? I'll put my code below:
PKCS11 pkcs11 = PKCS11.getInstance("C:\\Windows\\System32\\example.dll", "C_GetFunctionList", null,false);
long[] slotList = pkcs11.C_GetSlotList(true);
String providerString = "name=*\nlibrary=C:\\Windows\\System32\\example.dll\n" + "slot=" + slotList [0];
SunPKCS11 sunPKCS11 = new SunPKCS11(new ByteArrayInputStream(providerString .getBytes()));
Provider provider = sunPKCS11;
KeyStore keyStore = KeyStore.getInstance("PKCS11", provider);
keyStore.load(null, password);
keyStore.aliases();
Security.addProvider(keyStore.getProvider());
List<String> aliases = Collections.list(keyStore.aliases());
String alias = aliases.get(0);
PrivateKey pk = (PrivateKey)keyStore.getKey(alias,password);
Certificate[] certChain = new Certificate[1];
certChain[0] = signerCert;
PdfReader reader = new PdfReader(inputData);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
PdfStamper stamper = PdfStamper.createSignature(reader, outStream, '\0',null,true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
String fieldName = keyStore.getCertificateAlias(signerCert).replaceAll(".","");
appearance.setVisibleSignature(new Rectangle(420, 10, 70, 85), pageNumber,fieldName);
ExternalSignature es = new PrivateKeySignature(pk, DigestAlgorithms.SHA256,
keyStore.getProvider().getName());
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance,
digest, es,
certChain, null,
null, null,
0, CryptoStandard.CADES);
return outStream.toByteArray();
Why does it work with SHA-1 and not SHA-2? Where do you think the problem arises?
There are mismatches and errors in your signature.
download.pdf
This is the example file you shared in a comment to your question
Mismatch of Document Digest
The SHA-256 hash value of the signed bytes of your PDF is
9356BCD36F172806A3DCE7F062A66441E7C1DDC9203ABDAA0154A3F19208C8E3
but the embedded signature container claims it to be
5F892978FF2459157D631809A05F5DBCFCB55800236D2D5C3E4E4D94577012B4
According to your code that should not happen. Are you sure that PDF has been created by the code in your question? Or have you somehow changed it as you indicated by your I changed my hash like this comment and created the example document thereafter? Then this discrepancy most likely is caused by your change.
Broken Raw RSA Signature
After decrypting the raw signature bytes and removing the padding one gets
3031300D0609608648016503040201050004201DC71B824BAA3C7EC6744A0941CFADDAA893E8C1
This is incomplete. It corresponds to
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST Algorithm)
NULL
OCTET STRING (32 byte) 1DC71B824BAA3C7EC6744A0941CFADDAA893E8C1XXXXXXXXXXXXXXXXXXXXXXXX
with the 12 bytes for that XXXXXXXXXXXXXXXXXXXXXXXX piece missing.
Thus, it looks like the signing device does not really support SHA256withRSA, at least not in combination with the example.dll PKCS#11 driver and the SunPKCS11 security provider.
As an aside, the OCTET STRING there should have been
EC7FCC5D003DFEC58B0ECB49CEEAD28495FFA8D798A1A88DA6051C1857B971EC
Thus, it looks like here is another mismatch, the 1DC71B824BAA3C7EC6744A0941CFADDAA893E8C1 actually there appears not to be related to this value.
SHA256.pdf
Can you check out this one? this one is made with itext's library and no code was changed.
In this file there indeed are no hash mismatches anymore, merely the signature value is cut off, here
3031300D0609608648016503040201050004204C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC1
corresponding to
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST Algorithm)
NULL
OCTET STRING (32 byte) 4C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC1XXXXXXXXXXXXXXXXXXXXXXXX
The complete OCTET STRING should have been
4C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC19048B5E53D468FE6A8E4E973
So apparently indeed the chain of your signing device, the example.dll PKCS#11 driver, and the SunPKCS11 security provider from your JRE does not support SHA256withRSA.
In order to add docuemnt the timestamp, using itext, we have com.itextpdf.text.pdf.security.TSAClient abstract interface.
but how to get TimeStamp Certificate from the PDF file?
You can call the AcroFields method verifySignature for signature fields containing document timestamps, too, and query its result for the certificates.
PdfReader reader = ...;
AcroFields fields = reader.getAcroFields();
List<String> names = fields.getSignatureNames();
String signatureName = names.get(names.size() - 1);
PdfPKCS7 pkcs7 = fields.verifySignature(signatureName);
System.out.println(String.format("Checking %ssignature %s", pkcs7.isTsp() ? "document-level timestamp " : "", signatureName));
Certificate[] chain = pkcs7.getSignCertificateChain();
This code inspects the outermost signature or document time stamp of a document and returns that signature's or time stamp's certificate chain as far as it is known.
You might want to look at the LtvVerifier class (from which I extracted the code above) for verification of all signatures and document timestamps and read section 5.4.4 Validating an LTV document in Digital Signatures for PDF documents for the use in context.
I'm trying to draw QR barcodes in a PDF file using iTextSharp. If I'm using English text the barcodes are fine, they are decoded properly, but if I'm using Chinese text, the barcode is decoded as question marks. For example this character '测' (\u6D4B) is decoded as '?'. I tried all supported character sets, but none of them helped.
What combination of parameters should I use for the QR barcode in iTextSharp in order to encode correctly Chinese text?
iText and iTextSharp apparently don't natively support this but you can write some code to handle this on your own. The trick is to get the QR code parser to work with just an arbitrary byte array instead of a string. What's really nice is that the iTextSharp code is almost ready for this but doesn't expose the functionality. Unfortunately many of the required classes are sealed so you can't just subclass them, you'll have to recreate them. You can either download the entire source and add these changes or just create separate classes with the same names. (Please check over the license to make sure you are allowed to do this.) My changes below don't have any error correction so make sure you do that, too.
The first class that you'll need to recreate is iTextSharp.text.pdf.qrcode.BlockPair and the only change you'll need to make is to make the constructor public instead of internal. (You only need to do this if you are creating your own code and not modifying the existing code.)
The second class is iTextSharp.text.pdf.qrcode.Encoder. This is where we'll make the most changes. Add an overload to Append8BitBytes that looks like this:
static void Append8BitBytes(byte[] bytes, BitVector bits) {
for (int i = 0; i < bytes.Length; ++i) {
bits.AppendBits(bytes[i], 8);
}
}
The string version of this method converts text to a byte array and then uses the above so we're just cutting out the middle man. Next, add a new overload to the constructor that takes in a byte array instead of a string. We'll then just cut out the string detection part and force the system to byte-mode, otherwise the code below is pretty much the same.
public static void Encode(byte[] bytes, ErrorCorrectionLevel ecLevel, IDictionary<EncodeHintType, Object> hints, QRCode qrCode) {
String encoding = DEFAULT_BYTE_MODE_ENCODING;
// Step 1: Choose the mode (encoding).
Mode mode = Mode.BYTE;
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
BitVector dataBits = new BitVector();
Append8BitBytes(bytes, dataBits);
// Step 3: Initialize QR code that can contain "dataBits".
int numInputBytes = dataBits.SizeInBytes();
InitQRCode(numInputBytes, ecLevel, mode, qrCode);
// Step 4: Build another bit vector that contains header and data.
BitVector headerAndDataBits = new BitVector();
// Step 4.5: Append ECI message if applicable
if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) {
CharacterSetECI eci = CharacterSetECI.GetCharacterSetECIByName(encoding);
if (eci != null) {
AppendECI(eci, headerAndDataBits);
}
}
AppendModeInfo(mode, headerAndDataBits);
int numLetters = dataBits.SizeInBytes();
AppendLengthInfo(numLetters, qrCode.GetVersion(), mode, headerAndDataBits);
headerAndDataBits.AppendBitVector(dataBits);
// Step 5: Terminate the bits properly.
TerminateBits(qrCode.GetNumDataBytes(), headerAndDataBits);
// Step 6: Interleave data bits with error correction code.
BitVector finalBits = new BitVector();
InterleaveWithECBytes(headerAndDataBits, qrCode.GetNumTotalBytes(), qrCode.GetNumDataBytes(),
qrCode.GetNumRSBlocks(), finalBits);
// Step 7: Choose the mask pattern and set to "qrCode".
ByteMatrix matrix = new ByteMatrix(qrCode.GetMatrixWidth(), qrCode.GetMatrixWidth());
qrCode.SetMaskPattern(ChooseMaskPattern(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(),
matrix));
// Step 8. Build the matrix and set it to "qrCode".
MatrixUtil.BuildMatrix(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(),
qrCode.GetMaskPattern(), matrix);
qrCode.SetMatrix(matrix);
// Step 9. Make sure we have a valid QR Code.
if (!qrCode.IsValid()) {
throw new WriterException("Invalid QR code: " + qrCode.ToString());
}
}
The third class is iTextSharp.text.pdf.qrcode.QRCodeWriter and once again we just need to add an overloaded Encode method supports a byte array and that calls are new constructor created above:
public ByteMatrix Encode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
if (hints != null && hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
errorCorrectionLevel = (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION];
QRCode code = new QRCode();
Encoder.Encode(bytes, errorCorrectionLevel, hints, code);
return RenderResult(code, width, height);
}
The last class is iTextSharp.text.pdf.BarcodeQRCode which we once again add our new constructor overload:
public BarcodeQRCode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
newCode.QRCodeWriter qc = new newCode.QRCodeWriter();
bm = qc.Encode(bytes, width, height, hints);
}
The last trick is to make sure when calling this that you include the byte order mark (BOM) so that decoders know to decode this properly, in this case UTF-8.
//Create an encoder that supports outputting a BOM
System.Text.Encoding enc = new System.Text.UTF8Encoding(true, true);
//Get the BOM
byte[] bom = enc.GetPreamble();
//Get the raw bytes for the string
byte[] bytes = enc.GetBytes("测");
//Combine the byte arrays
byte[] final = new byte[bom.Length + bytes.Length];
System.Buffer.BlockCopy(bom, 0, final, 0, bom.Length);
System.Buffer.BlockCopy(bytes, 0, final, bom.Length, bytes.Length);
//Create are barcode using our new constructor
var q = new BarcodeQRCode(final, 100, 100, null);
//Add it to the document
doc.Add(q.GetImage());
Looks like you may be out of luck. I tried too and got the same results as you did. Then looked at the Java API:
"*CHARACTER_SET the values are strings and can be Cp437, Shift_JIS and
ISO-8859-1 to ISO-8859-16. The default value is ISO-8859-1.*"
Lastly, looked at the iTextSharp BarcodeQRCode class source code to confirm that only those characters sets are supported. I'm by no means an authority on Unicode or encoding, but according to ISO/IEC 8859, the character sets above won't work for Chinese.
Essentially the same trick that Chris has done in his answer could be implemented by specifying UTF-8 charset in barcode hints.
var hints = new Dictionary<EncodeHintType, Object>() {{EncodeHintType.CHARACTER_SET, "UTF-8"}};
var q = new BarcodeQRCode("\u6D4B", 100, 100, hints);
If you want to be more safe, you can start your string with BOM character '\uFEFF', like Chris suggested, so it would be "\uFEFF\u6D4B".
UTF-8 is unfortunately not supported by QR codes specification, and there are a lot of discussions on this subject, but the fact is that most QR code readers will correctly read the code created by this method.
I am trying to do some symmetric encryption on some data with the Zend_Filter_Encrypt function. The problem is if i encrypt some data and then later decrypt it, there are nullbytes behind the decrypted data and I have no idea why.
For instance:
Plaintext: test Encrypted: ����pk� Decrypted: test����
It seems to be padding nullbytes at the end of the decrypted text to make it's length equal to some 2^n (a string with 11 characters is padded to fit 16 => 2^4). The most obvious thing would be to just strip these characters but I want to know why this is happening...
This is the code I'm using, which is different than how the documentation wants you to do it because their code just doesn't work for me (see: http://framework.zend.com/manual/en/zend.filter.set.html)
define('VECTOR','EXfPCW23'); //example, not the actual used VECTOR / KEY
$key = 'lolwatlolwat';
public function encryptPassword($password, $key)
{
$filter = new Zend_Filter_Encrypt();
$filter->setEncryption(array('key' => $key));
$filter->setVector(VECTOR);
return $filter->filter($password);
}
public function decryptPassword($password, $key)
{
$filter = new Zend_Filter_Decrypt();
$filter->setEncryption(array('key' => $key));
$filter->setVector(VECTOR);
return $filter->filter($password);
}
You have to use rtrim function on Decrypt string.
Example:
public function decryptPassword($password, $key)
{
$filter = new Zend_Filter_Decrypt();
$filter->setEncryption(array('key' => $key));
$filter->setVector(VECTOR);
return rtrim($filter->filter($password);
}
Does the Zend documentation tell you how to specify the padding? If so then specify a reversible padding; as you have found, zero padding is not reversible. Otherwise, find out what size padded plaintext Zend is expecting and add PKCS7 padding yourself. This is easily recognisable and removable afterwards.