Cryptlib OpenPGP enveloping occasionally produces unreadable data

Lahiru Dissanayake <[email protected]> Wed, 18 Jun 2014 12:55:36 +0800
Newsgroups gmane.comp.encryption.cryptlib
Message-ID <CAHeAcfDxUM3fju5RzsYDuU-xFHC8iYNiw6yWJo1U7Ze1YakMmg@mail.gmail.com>
Hi Peter,

I notice that when we perform openpgp enveloping, cryptlib occasionally
produces data that cannot be de-enveloped by itself. I've attached the code
for a test I wrote for this. When I run it, cryptlib gives
CRYPT_ERROR_BADDATA about 5-10 times out of a 1000.

I've also attached the changes we've made to cryptlib release 3.4.2 based
on the bug fixes you've suggested before, to make sure that they do not
cause this.

I'd appreciate it if you could look into this matter.

Thanks,
Lahiru

_______________________________________________
Cryptlib mailing list
[email protected] via Mail: [email protected]
Archive: ftp://ftp.franken.de/pub/crypt/cryptlib/archives/
http://news.gmane.org/gmane.comp.encryption.cryptlib
Posts from non-subscribed addresses are blocked to prevent spam, please
subscribe in order to post messages.
main.c (text/x-csrc, 3.4 KB)
//
//  main.c
//  CryptlibEncryption
//
//  Created by Lahiru Dissanayake on 6/17/14.
//  Copyright (c) 2014 Lahiru Dissanayake. All rights reserved.
//

#include <stdio.h>
#import <stdlib.h>
#import <assert.h>
#import "cryptlib.h"

void testPGPEncryptionDecryption();

int main(int argc, const char * argv[])
{
    int status = cryptInit();
    assert(cryptStatusOK(status));
    testPGPEncryptionDecryption();
    cryptEnd();
    return 0;
}

void testPGPEncryptionDecryption() {
    
    CRYPT_CONTEXT pgpPrivateKeyContext;
    int status = cryptCreateContext( &pgpPrivateKeyContext, CRYPT_UNUSED, CRYPT_ALGO_RSA );
    status = cryptSetAttributeString( pgpPrivateKeyContext, CRYPT_CTXINFO_LABEL, "Tom", 3);
    status = cryptGenerateKey( pgpPrivateKeyContext );
    
    int messageLength = 50;
    char *message = malloc(messageLength); //some random data
    
    int testCount = 1000;
    int failCount = 0;
    
    for (int i=0; i<testCount; i++) {
        printf("Iteration %d...\n", i);
        
        char envelopedData[10000];
        
        CRYPT_ENVELOPE cryptEnvelope;
        int bytesCopied;
        
        //encryption
        status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_PGP );
        status = cryptSetAttribute( cryptEnvelope, CRYPT_OPTION_ENCR_ALGO, CRYPT_ALGO_AES );
        status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY, pgpPrivateKeyContext );
        status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, messageLength );
        assert(cryptStatusOK(status));
        
        status = cryptPushData( cryptEnvelope, message, messageLength, &bytesCopied );
        assert(bytesCopied==messageLength);
        status = cryptFlushData( cryptEnvelope );
        status = cryptPopData( cryptEnvelope, envelopedData, 10000, &bytesCopied );
        assert(cryptStatusOK(status));
        status = cryptDestroyEnvelope( cryptEnvelope );
        
        assert(bytesCopied<10000);
        
        int envelopSize = bytesCopied;
        
        //decryption
        status = cryptCreateEnvelope(&cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO);
        status = cryptPushData(cryptEnvelope, envelopedData, envelopSize, &bytesCopied);
        
        if (status==CRYPT_ERROR_BADDATA) { //oops! can't decrypt
            printf("Bad data detected!\n");
            failCount++;
            continue;
        }
        
        CRYPT_ATTRIBUTE_TYPE requiredAttribute = 0;
        cryptGetAttribute(cryptEnvelope, CRYPT_ATTRIBUTE_CURRENT, (int *)&requiredAttribute);
        assert(requiredAttribute==CRYPT_ENVINFO_PRIVATEKEY);
        status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_PRIVATEKEY, pgpPrivateKeyContext );
        status = cryptFlushData(cryptEnvelope);
        
        assert(cryptStatusOK(status));
        
        char decryptedData[10000];
        status = cryptPopData(cryptEnvelope, decryptedData, 10000, &bytesCopied);
        
        if (bytesCopied != messageLength) {
            printf("Message size difference!!\n");
            failCount++;
            continue;
        }
        
        for (int idx=0; idx<messageLength; idx++) {
            if (message[idx] != decryptedData[idx]) {
                printf("Decrypted data doesn't match original!!\n");
                failCount++;
                continue;
            }
        }
        
        cryptDestroyEnvelope(cryptEnvelope);
    }
    
    free(message);
    
    printf("%d failures out of %d\n", failCount, testCount);
}
clault_changes.patch (application/octet-stream, 11 KB)
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/context/kg_rsa.c /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/context/kg_rsa.c
--- /Users/Lahiru/Downloads/cryptlib/cl342/context/kg_rsa.c	2011-05-25 03:39:34.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/context/kg_rsa.c	2014-06-18 12:28:02.000000000 +0800
@@ -379,8 +379,8 @@ static int checkRSAPrivateKeyComponents(
 		return( CRYPT_ARGERROR_STR1 );
 
 	/* Verify that u < p, where u was calculated as q^-1 mod p */
-	if( BN_cmp( &pkcInfo->rsaParam_u, p ) >= 0 )
-		return( CRYPT_ARGERROR_STR1 );
+//	if( BN_cmp( &pkcInfo->rsaParam_u, p ) >= 0 )
+//		return( CRYPT_ARGERROR_STR1 );
 
 	/* A very small number of systems/compilers can't handle 32 * 32 -> 64
 	   ops which means that we have to use 16-bit bignum components.  For 
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/envelope/env_attr.c /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/envelope/env_attr.c
--- /Users/Lahiru/Downloads/cryptlib/cl342/envelope/env_attr.c	2012-08-10 15:59:10.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/envelope/env_attr.c	2014-06-18 12:27:59.000000000 +0800
@@ -833,12 +833,16 @@ static int checkOtherAttribute( INOUT EN
 				envelopeInfoPtr->usage != ACTION_SIGN )
 				return( exitErrorInited( envelopeInfoPtr, 
 										 CRYPT_ENVINFO_SIGNATURE ) );
-			if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
-				envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
-				{
-				/* See the long comment for CRYPT_ENVINFO_CONTENTTYPE */
-				return( CRYPT_ARGERROR_VALUE );
-				}
+            if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
+                ( envelopeInfoPtr->contentType != CRYPT_CONTENT_NONE && \
+                envelopeInfoPtr->contentType != CRYPT_CONTENT_DATA ) )
+            {
+                /* See the long comment for CRYPT_ENVINFO_CONTENTTYPE.  In
+                    short, the processing for signing anything other than
+                    plain data is undefined in PGP, so we don't allow
+                    signature types for this content type */
+                return( CRYPT_ARGERROR_VALUE );
+            }
 			*usage = ACTION_SIGN;
 			return( CRYPT_OK );
 
@@ -1287,7 +1291,7 @@ int setEnvelopeAttribute( INOUT ENVELOPE
 	{ CRYPT_ENVINFO_SIGNATURE,		formatAll,		ACTION_NONE,	MESSAGE_CHECK_NONE,		0 },
 	{ CRYPT_ENVINFO_SIGNATURE_EXTRADATA, formatAllEnvSMIME, ACTION_NONE, MESSAGE_CHECK_NONE, 0 },
 	{ CRYPT_ENVINFO_PUBLICKEY,		formatAllEnv,	ACTION_CRYPT,	MESSAGE_CHECK_PKC_ENCRYPT, 0 },
-	{ CRYPT_ENVINFO_PRIVATEKEY,		formatAllDeenv,	ACTION_CRYPT,	MESSAGE_CHECK_PKC_DECRYPT, 0 },
+	{ CRYPT_ENVINFO_PRIVATEKEY,     formatAll,      ACTION_CRYPT, MESSAGE_CHECK_PKC_DECRYPT, 0 },
 	{ CRYPT_ENVINFO_SESSIONKEY,		formatAllCMS,	ACTION_CRYPT,	MESSAGE_CHECK_CRYPT,	0 },
 	{ CRYPT_ENVINFO_HASH,			formatAll,		ACTION_SIGN,	MESSAGE_CHECK_HASH,		ENVELOPE_DETACHED_SIG },
 	{ CRYPT_ENVINFO_TIMESTAMP,		formatAllEnvSMIME, ACTION_SIGN,	MESSAGE_CHECK_NONE,		0 },
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/envelope/pgp_env.c /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/envelope/pgp_env.c
--- /Users/Lahiru/Downloads/cryptlib/cl342/envelope/pgp_env.c	2012-03-17 21:12:46.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/envelope/pgp_env.c	2014-06-18 12:27:59.000000000 +0800
@@ -802,8 +802,22 @@ static int emitPreamble( INOUT ENVELOPE_
 		/* Make sure that we start a new segment if we try to add any data */
 		envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
 
-		/* Before we can finish we have to push in the inner data header */
-		envelopeInfoPtr->envState = ENVSTATE_DATA;
+            /* If the content type is plain data then we have to push in the
+             inner data header before we exit */
+            if( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
+                envelopeInfoPtr->envState = ENVSTATE_DATA;
+            else
+            {
+                /* We've processed the header, if this is signed data then we
+                 start hashing from this point.  The PGP RFCs are wrong in
+                 this regard in that only the payload is hashed and not the
+                 entire packet */
+                if( envelopeInfoPtr->usage == ACTION_SIGN )
+                    envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
+                
+                /* We're finished */
+                envelopeInfoPtr->envState = ENVSTATE_DONE;
+            }
 		}
 
 	/* Handle data payload information */
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/kernel/attr_acl.c /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/kernel/attr_acl.c
--- /Users/Lahiru/Downloads/cryptlib/cl342/kernel/attr_acl.c	2012-10-13 20:48:00.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/kernel/attr_acl.c	2014-06-18 12:27:59.000000000 +0800
@@ -277,7 +277,7 @@ static const ATTRIBUTE_ACL FAR_BSS gener
 
 static const RANGE_SUBRANGE_TYPE FAR_BSS allowedEncrAlgoSubranges[] = {
 	{ CRYPT_ALGO_3DES, CRYPT_ALGO_3DES },		/* No DES */
-	{ CRYPT_ALGO_AES, CRYPT_ALGO_BLOWFISH },	/* No IDEA, CAST, RC2, RC4, RC5 */
+	{ CRYPT_ALGO_CAST, CRYPT_ALGO_BLOWFISH },       /* No IDEA */ //change to add CAST5 as allowed algo //{ CRYPT_ALGO_AES, CRYPT_ALGO_BLOWFISH },	/* No IDEA, CAST, RC2, RC4, RC5 */
 	{ CRYPT_ERROR, CRYPT_ERROR } 
 	};
 static const int FAR_BSS allowedLDAPObjectTypes[] = {
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/makefile /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/makefile
--- /Users/Lahiru/Downloads/cryptlib/cl342/makefile	2012-12-14 03:31:22.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/makefile	2014-06-18 12:27:59.000000000 +0800
@@ -73,8 +73,8 @@ DYLIBNAME = lib$(PROJ).$(MAJ).$(MIN).dyl
 # Further cc flags are gathered dynamically at runtime via the ccopts.sh
 # script.
 
-CFLAGS		= -c -D__UNIX__ -DNDEBUG -I.
-CFLAGS_DEBUG = -c -D__UNIX__ -I. -g3 -ggdb -O0
+CFLAGS		= -c -DNDEBUG -I. 
+CFLAGS_DEBUG = -c -I. -g3 -ggdb -O0
 
 # Paths and command names.  We have to be careful with comments attached to
 # path defines because some makes don't strip trailing spaces.
@@ -239,7 +239,7 @@ MISCOBJS	= $(OBJPATH)int_api.o $(OBJPATH
 			  $(OBJPATH)int_env.o $(OBJPATH)int_err.o $(OBJPATH)int_mem.o \
 			  $(OBJPATH)int_string.o $(OBJPATH)int_time.o $(OBJPATH)java_jni.o \
 			  $(OBJPATH)os_spec.o $(OBJPATH)pgp_misc.o $(OBJPATH)random.o \
-			  $(OBJPATH)rand_x917.o $(OBJPATH)unix.o $(OBJPATH)user.o \
+			  $(OBJPATH)rand_x917.o $(OBJPATH)iOS.o $(OBJPATH)user.o \
 			  $(OBJPATH)user_attr.o $(OBJPATH)user_cfg.o $(OBJPATH)user_rw.o
 
 SESSOBJS	= $(OBJPATH)certstore.o $(OBJPATH)cmp.o $(OBJPATH)cmp_cli.o \
@@ -1166,8 +1166,8 @@ $(OBJPATH)random.o:		$(CRYPT_DEP) random
 $(OBJPATH)rand_x917.o:	$(CRYPT_DEP) random/rand_x917.c
 						$(CC) $(CFLAGS) -o $(OBJPATH)rand_x917.o random/rand_x917.c
 
-$(OBJPATH)unix.o:		$(CRYPT_DEP) random/unix.c
-						$(CC) $(CFLAGS) -o $(OBJPATH)unix.o random/unix.c
+$(OBJPATH)iOS.o:		$(CRYPT_DEP) random/iOS.c
+						$(CC) $(CFLAGS) -o $(OBJPATH)iOS.o random/iOS.c
 
 $(OBJPATH)user.o:		$(CRYPT_DEP) misc/user.h misc/user.c
 						$(CC) $(CFLAGS) -o $(OBJPATH)user.o misc/user.c
@@ -2330,13 +2330,19 @@ target-freertos-ppc:
 
 # Apple iOS hosted on OS X.
 
+XCODE_BASE="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer"
 target-ios:
 	@make directories
 	@make OSNAME=iOS target-init
-	make $(XDEFINES) OSNAME=iOS CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cc \
-		CFLAGS="$(XCFLAGS) -DCONFIG_DATA_LITTLEENDIAN -fomit-frame-pointer -O2 \
+	make $(XDEFINES) OSNAME=iOS \
+		CC=$(XCODE_BASE)/usr/bin/gcc \
+		LD=$(XCODE_BASE)/usr/bin/ld \
+		AR=$(XCODE_BASE)/usr/bin/ar \
+		STRIP=$(XCODE_BASE)/usr/bin/strip \
+		CFLAGS="$(XCFLAGS) -D__UNIX__ -DCONFIG_DATA_LITTLEENDIAN -fomit-frame-pointer -O2 \
 		-D_REENTRANT -arch armv7 \
-		-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk"
+		-isysroot $(XCODE_BASE)/SDKs/iPhoneOS6.1.sdk" \
+		LDFLAGS="-arch armv7" 
 	make $(SLIBNAME) OBJPATH=$(OBJPATH) CROSSCOMPILE=1 OSNAME=iOS
 
 # Embedded Linux.  Note that we don't have to perform the 'make target-init'
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/random/ios.c /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/random/ios.c
--- /Users/Lahiru/Downloads/cryptlib/cl342/random/ios.c	1970-01-01 07:30:00.000000000 +0730
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/random/ios.c	2014-06-18 12:28:01.000000000 +0800
@@ -0,0 +1,55 @@
+//
+//  ios.c
+//  cryptlib
+//
+//  Created by Lahiru Dissanayake on 12/4/13.
+//  Copyright (c) 2013 Clault Pte Ltd. All rights reserved.
+//
+
+//#ifdef TARGET_IPHONE_SIMULATOR
+//#include "unix.c"
+//#else
+
+#include <stdio.h>
+#include <Security/Security.h>
+#include "crypt.h"
+#include "random.h"
+
+#define RANDOM_BUFSIZE	4096
+
+void fastPoll( void )
+{
+	RANDOM_STATE randomState;
+	uint8_t buffer[ RANDOM_BUFSIZE + 8 ];
+    
+    initRandomData( randomState, buffer, RANDOM_BUFSIZE );
+    
+    uint8_t *randomData = malloc(RANDOM_BUFSIZE);
+    SecRandomCopyBytes(kSecRandomDefault, RANDOM_BUFSIZE, randomData);
+    addRandomData( randomState, randomData, RANDOM_BUFSIZE );
+    free(randomData);
+    
+    endRandomData( randomState, 50 );
+}
+
+void slowPoll( void )
+{
+	RANDOM_STATE randomState;
+	uint8_t buffer[ RANDOM_BUFSIZE + 8 ];
+    
+    initRandomData( randomState, buffer, RANDOM_BUFSIZE );
+    
+    uint8_t *randomData = malloc(RANDOM_BUFSIZE);
+    SecRandomCopyBytes(kSecRandomDefault, RANDOM_BUFSIZE, randomData);
+    addRandomData( randomState, randomData, RANDOM_BUFSIZE );
+    free(randomData);
+    
+    endRandomData( randomState, 100 );
+}
+
+void initRandomPolling( ) { }
+void endRandomPolling( ) { }
+int waitforRandomCompletion( const BOOLEAN force ) { return CRYPT_OK; }
+BOOLEAN checkForked() { return FALSE; }
+
+//#endif
\ No newline at end of file
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/tools/buildlib.sh /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/tools/buildlib.sh
--- /Users/Lahiru/Downloads/cryptlib/cl342/tools/buildlib.sh	2012-11-06 03:55:52.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/tools/buildlib.sh	2014-06-18 12:28:00.000000000 +0800
@@ -75,7 +75,7 @@ case $OSNAME in
 		echo "Need to set up ucLinux link command" ;;
 
 	*)
-		$AR rcs $LIBNAME $* || \
-		( $AR rc $LIBNAME $* && ranlib $LIBNAME )
+		echo "$AR rcs $LIBNAME $* || ( $AR rc $LIBNAME $* && ranlib $LIBNAME )"
+		$AR rcs $LIBNAME $* || ( $AR rc $LIBNAME $* && ranlib $LIBNAME )
 
 esac
diff -rupN /Users/Lahiru/Downloads/cryptlib/cl342/tools/buildsharedlib.sh /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/tools/buildsharedlib.sh
--- /Users/Lahiru/Downloads/cryptlib/cl342/tools/buildsharedlib.sh	2012-11-06 03:55:40.000000000 +0800
+++ /Users/Lahiru/Documents/Projects/ios/cryptlib-3.4.2/tools/buildsharedlib.sh	2014-06-18 12:28:00.000000000 +0800
@@ -118,6 +118,9 @@ case $OSNAME in
 		fi
 		$STRIP $LIBNAME ;;
 
+	'iOS')
+        echo "Shared library is not needed for iOS."
+        ;;
 	*)
 		if [ `$LD -v 2>&1 | grep -c gcc` -gt 0 -a \
 			`gcc -Wl,-Bsymbolic 2>&1 | grep -c unrecognized` = 0 ] ; then