From bb9feca663ce701ea2cf0403b1f63d660e1723c1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 17:28:12 -0400 Subject: [PATCH 01/90] update C build system to simplify the process of building on Debian-derivs --- .gitignore | 3 +++ src/c/GNUmakefile | 48 ++++++++++++++++----------------------- src/c/libjavagnupg.32.so | Bin 161430 -> 0 bytes src/c/libjavagnupg.64.so | Bin 186896 -> 0 bytes 4 files changed, 23 insertions(+), 28 deletions(-) create mode 100644 .gitignore delete mode 100755 src/c/libjavagnupg.32.so delete mode 100755 src/c/libjavagnupg.64.so diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b65e85c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +src/c/*.o +src/c/libjavagnupg.so diff --git a/src/c/GNUmakefile b/src/c/GNUmakefile index a43e525..451c64b 100644 --- a/src/c/GNUmakefile +++ b/src/c/GNUmakefile @@ -1,16 +1,9 @@ -# to use the JAVA_HOME var in the environment, use the `-e' flag to make -ifeq ($(JAVA_HOME),,) -JAVA_HOME := /www/home/tcadm/local/jdk-amd64 -#JAVA_HOME := /opt/java/jdk1.5.0_06 -#JAVA_HOME := /usr/lib/jvm/java-1.5.0-sun -#JAVA_HOME := /usr/local/jdk1.4.2 -endif +# to override this JAVA_HOME, use the `-e' flag to make, or call it like: +# make JAVA_HOME=/opt/java +JAVA_HOME := $(shell readlink -f /usr/bin/javac | sed "s:/bin/javac::") -# set this from the command line to enforce a particular OS-bitness -BITS := $(shell /bin/uname -m | grep ".*_[0-9]\+" | sed "s/.*_\([0-9]\+\)/\1/") - -JAVAGNUPG_LIB := libjavagnupg -JNISRC := $(wildcard GnuPG*.c) +JAVAGNUPG_LIB := libjavagnupg.so +JNISRC := GnuPGContext.c GnuPGData.c GnuPGGenkeyResult.c GnuPGKey.c GnuPGSignature.c JNI_CLASSES := $(patsubst %.c, com.freiheit.gnupg.%, $(JNISRC)) JNI_HEADERS := $(patsubst %.c, com_freiheit_gnupg_%.h, $(JNISRC)) SOURCES := $(JNISRC) gpgmeutils.c @@ -23,26 +16,22 @@ JAVA := $(JAVA_HOME)/bin/java CC := gcc INSTALL := install -m 644 -MARCH := -ifneq ($(BITS),) -MARCH := -m$(BITS) -else -BITS := 32 -endif DEBUG := -g -CFLAGS := $(MARCH) -Werror -Wall -Wno-deprecated-declarations -fPIC $(shell gpgme-config --cflags) -CPPFLAGS := -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux +CFLAGS := -Werror -Wall -Wno-deprecated-declarations -Wno-unused-but-set-variable \ + -fPIC $(shell gpgme-config --cflags) +CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ + -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux C_IMPL := ./src/c JAVA_BUILD := ../../build LDFLAGS := $(shell gpgme-config --thread=pthread --libs) -lib: $(JAVAGNUPG_LIB).$(BITS).so +lib: $(JAVAGNUPG_LIB) -$(JAVAGNUPG_LIB).$(BITS).so: $(OBJECTS) +$(JAVAGNUPG_LIB): $(OBJECTS) $(CC) $(DEBUG) -shared $(CFLAGS) $^ -o $@ $(LDFLAGS) $(INSTALL) -m 755 -d $(JAVA_BUILD)/c - $(INSTALL) $(JAVAGNUPG_LIB).$(BITS).so $(JAVA_BUILD)/c + $(INSTALL) $(JAVAGNUPG_LIB) $(JAVA_BUILD)/c header: $(JNI_HEADERS) @@ -53,12 +42,15 @@ mids: $(JAVAP) -classpath $(JAVA_BUILD) -s -p $(JNI_CLASSES) clean: - @echo "NOT deleting the shared libraries. Use \`distclean' target to remove them." rm -f $(OBJECTS) *~ - -distclean: - $(MAKE) clean - rm -f $(JAVAGNUPG_LIB).*.so + rm -f $(JAVAGNUPG_LIB) + +test: + echo "JAVA_HOME: --$(JAVA_HOME)--" + echo "JNISRC: $(JNISRC)" + echo "JNI_CLASSES: $(JNI_CLASSES)" + echo "JNI_HEADERS: $(JNI_HEADERS)" + echo "SOURCES: $(SOURCES)" %.o: %.c $(JNI_HEADERS) gpgmeutils.h $(CC) $(DEBUG) $(CFLAGS) $(CPPFLAGS) -c $< diff --git a/src/c/libjavagnupg.32.so b/src/c/libjavagnupg.32.so deleted file mode 100755 index 0ef259770decd390186d0da4af04d49ae100d778..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161430 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 ZGfS!ItUF7j!rT=)H1`)BP^m-qe*sLAOr-z- diff --git a/src/c/libjavagnupg.64.so b/src/c/libjavagnupg.64.so deleted file mode 100755 index 2f4f4e1a7bae0b4e6b6b9e47cc262afa4a61430a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186896 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 Date: Tue, 14 Aug 2012 17:32:45 -0400 Subject: [PATCH 02/90] rename everything to gnupg-for-java to keep the name consistent throughout --- .gitignore | 2 +- build.properties | 2 +- build.xml | 4 ++-- runTests.sh | 2 +- src/c/GNUmakefile | 10 +++++----- src/java/com/freiheit/gnupg/GnuPGContext.java | 12 ++++++------ src/java/com/freiheit/gnupg/GnuPGKey.java | 4 ++-- src/java/com/freiheit/gnupg/GnuPGPeer.java | 6 +++--- src/java/com/freiheit/gnupg/GnuPGSignature.java | 4 ++-- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index b65e85c..a267242 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ build/ src/c/*.o -src/c/libjavagnupg.so +src/c/libgnupg-for-java.so diff --git a/build.properties b/build.properties index 7534499..016d361 100644 --- a/build.properties +++ b/build.properties @@ -1,6 +1,6 @@ # default build.properties -app.name=javagnupg +app.name=gnupg-for-java app.type=@APP-TYPE@ app.version=0.1.5-ascii-armor-linux-i386-ia64 app.customer=LGPL diff --git a/build.xml b/build.xml index cf4da56..d999c00 100644 --- a/build.xml +++ b/build.xml @@ -1,4 +1,4 @@ - + @@ -48,7 +48,7 @@ - + diff --git a/runTests.sh b/runTests.sh index 7942bab..bd6c1d2 100755 --- a/runTests.sh +++ b/runTests.sh @@ -1,4 +1,4 @@ #STYLE=textui STYLE=swingui #STYLE=awtui -java -cp dist/javagnupg-0.1.2-alpha.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.GnuPGTestSuite +java -cp dist/gnupg-for-java-0.1.2-alpha.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.GnuPGTestSuite diff --git a/src/c/GNUmakefile b/src/c/GNUmakefile index 451c64b..d77aa9c 100644 --- a/src/c/GNUmakefile +++ b/src/c/GNUmakefile @@ -2,7 +2,7 @@ # make JAVA_HOME=/opt/java JAVA_HOME := $(shell readlink -f /usr/bin/javac | sed "s:/bin/javac::") -JAVAGNUPG_LIB := libjavagnupg.so +GNUPG_LIB := libgnupg-for-java.so JNISRC := GnuPGContext.c GnuPGData.c GnuPGGenkeyResult.c GnuPGKey.c GnuPGSignature.c JNI_CLASSES := $(patsubst %.c, com.freiheit.gnupg.%, $(JNISRC)) JNI_HEADERS := $(patsubst %.c, com_freiheit_gnupg_%.h, $(JNISRC)) @@ -26,12 +26,12 @@ C_IMPL := ./src/c JAVA_BUILD := ../../build LDFLAGS := $(shell gpgme-config --thread=pthread --libs) -lib: $(JAVAGNUPG_LIB) +lib: $(GNUPG_LIB) -$(JAVAGNUPG_LIB): $(OBJECTS) +$(GNUPG_LIB): $(OBJECTS) $(CC) $(DEBUG) -shared $(CFLAGS) $^ -o $@ $(LDFLAGS) $(INSTALL) -m 755 -d $(JAVA_BUILD)/c - $(INSTALL) $(JAVAGNUPG_LIB) $(JAVA_BUILD)/c + $(INSTALL) $(GNUPG_LIB) $(JAVA_BUILD)/c header: $(JNI_HEADERS) @@ -43,7 +43,7 @@ mids: clean: rm -f $(OBJECTS) *~ - rm -f $(JAVAGNUPG_LIB) + rm -f $(GNUPG_LIB) test: echo "JAVA_HOME: --$(JAVA_HOME)--" diff --git a/src/java/com/freiheit/gnupg/GnuPGContext.java b/src/java/com/freiheit/gnupg/GnuPGContext.java index fc8f1c7..259c5ff 100644 --- a/src/java/com/freiheit/gnupg/GnuPGContext.java +++ b/src/java/com/freiheit/gnupg/GnuPGContext.java @@ -180,7 +180,7 @@ public String passphraseCallback(String hint, String passphraseInfo, long wasBad } private long[] getInternalRepresentationFromRecipients(GnuPGKey[] recipients) { - // note that these are pointers to addresses in the javagnupg shared lib + // note that these are pointers to addresses in the gnupg-for-java shared lib long recipientsInternals[] = new long[recipients.length]; for (int i=0; i < recipients.length; i++) { if (recipients[i] != null) @@ -304,7 +304,7 @@ public GnuPGKey[] searchKeys(String query) throws GnuPGException{ public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException{ if (hasNoRecipients(recipients) || plain == null || cipher == null) throw new GnuPGException("Encryption-Arguments not complete."); - // note that these are pointers to addresses in the javagnupg shared lib + // note that these are pointers to addresses in the gnupg-for-java shared lib long recipientsInternals[] = getInternalRepresentationFromRecipients(recipients); gpgmeOpEncrypt(this.getInternalRepresentation(), recipientsInternals, plain.getInternalRepresentation(), cipher.getInternalRepresentation()); @@ -454,7 +454,7 @@ public void genKey(String params,GnuPGData pub, GnuPGData secret) throws GnuPGEx */ public void setEngineInfo(int proto, String fileName, String homeDir){ - // note that this is a pointer to and address in the javagnupg shared lib + // note that this is a pointer to and address in the gnupg-for-java shared lib long ctx = getInternalRepresentation(); gpgmeCtxSetEngineInfo(ctx,proto,fileName,homeDir); } @@ -524,7 +524,7 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native long gpgmeGetTextmode(long l); private native void gpgmeSetTextmode(long l, long state); - private static final String NATIVE_LIBRARY_BASENAME = "libjavagnupg"; + private static final String NATIVE_LIBRARY_BASENAME = "libgnupg-for-java"; /* It is not possible, to load a shared library directly @@ -587,7 +587,7 @@ public void delete(GnuPGKey key, boolean allowSecret){ private static String getNativeLibraryName() { // if all fails we assume windblows - String libName = "/c/javagnupg"; + String libName = "/c/gnupg-for-java"; try { ProcessBuilder pb = new ProcessBuilder(new String[] { "/bin/uname", "-m" }); @@ -605,7 +605,7 @@ private static String getNativeLibraryName() { } String uName = sb.toString().trim(); - libName = uName.endsWith("_64") ? "/c/libjavagnupg.64" : "/c/libjavagnupg.32"; + libName = uName.endsWith("_64") ? "/c/libgnupg-for-java.64" : "/c/libgnupg-for-java.32"; } catch (Exception e) { System.err.println("Cannot execute 'uname'. Probably running on a non unix environment."); /* nothing here, may add some debug output */ diff --git a/src/java/com/freiheit/gnupg/GnuPGKey.java b/src/java/com/freiheit/gnupg/GnuPGKey.java index 315bb16..3ef0c49 100644 --- a/src/java/com/freiheit/gnupg/GnuPGKey.java +++ b/src/java/com/freiheit/gnupg/GnuPGKey.java @@ -33,7 +33,7 @@ public class GnuPGKey extends GnuPGPeer{ This is how then each key is instantiated on the java side from c. */ protected GnuPGKey(long ptr) { - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib setInternalRepresentation(ptr); } @@ -135,7 +135,7 @@ private String listSignatures(){ private GnuPGSignature getSignature(){ GnuPGSignature result = null; - // note that thhis is a pointer to an address in the javagnupg shared lib + // note that thhis is a pointer to an address in the gnupg-for-java shared lib long ptr = gpgmeGetSignature(getInternalRepresentation()); if (ptr != 0){ diff --git a/src/java/com/freiheit/gnupg/GnuPGPeer.java b/src/java/com/freiheit/gnupg/GnuPGPeer.java index 943e3f6..bac2cc2 100644 --- a/src/java/com/freiheit/gnupg/GnuPGPeer.java +++ b/src/java/com/freiheit/gnupg/GnuPGPeer.java @@ -21,14 +21,14 @@ @author Stefan Richter, stefan@freiheit.com */ public class GnuPGPeer{ - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib protected long _internalRepresentation; /** DO NOT USE IT. This is only use from inside the library. */ protected void setInternalRepresentation(long ptr){ - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib _internalRepresentation = ptr; } @@ -36,7 +36,7 @@ protected void setInternalRepresentation(long ptr){ DO NOT USE IT. This is only use from inside the library. */ protected long getInternalRepresentation(){ - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib return _internalRepresentation; } } diff --git a/src/java/com/freiheit/gnupg/GnuPGSignature.java b/src/java/com/freiheit/gnupg/GnuPGSignature.java index bf19229..e3c295a 100644 --- a/src/java/com/freiheit/gnupg/GnuPGSignature.java +++ b/src/java/com/freiheit/gnupg/GnuPGSignature.java @@ -38,7 +38,7 @@ public class GnuPGSignature extends GnuPGPeer{ @see com.freiheit.gnupg.GnuPGKey */ protected GnuPGSignature(long ptr){ - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib setInternalRepresentation(ptr); } @@ -162,7 +162,7 @@ public String toString(){ protected GnuPGSignature getNextSignature(){ GnuPGSignature result = null; - // note that this is a pointer to an address in the javagnupg shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib long next = gpgmeGetNextSignature(getInternalRepresentation()); if(next != 0){ From 4830b16367f81d1248de772557096b4793aac6d5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 20:42:21 -0400 Subject: [PATCH 03/90] convert to very plain JNI loading using System.loadLibrary() and JNI_OnLoad() --- src/c/GnuPGContext.c | 12 +- src/c/com_freiheit_gnupg_GnuPGContext.h | 7 - src/java/com/freiheit/gnupg/GnuPGContext.java | 131 +----------------- 3 files changed, 12 insertions(+), 138 deletions(-) diff --git a/src/c/GnuPGContext.c b/src/c/GnuPGContext.c index ea49c29..02d6ae8 100644 --- a/src/c/GnuPGContext.c +++ b/src/c/GnuPGContext.c @@ -76,9 +76,12 @@ passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, return GPG_ERR_NO_ERROR; } -JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeCheckVersion(JNIEnv * env, jclass cls) +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) { + _jvm = vm; + + // TODO set locale from the Java setting setlocale(LC_ALL, ""); //FIXME: The tests are hanging, when I use check_version, which is actually // initializing the threading subsystem...hmmm.. @@ -86,6 +89,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeCheckVersion(JNIEnv * env, jclass cls) //printf("VERSION: %s\n", version); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); + + return JNI_VERSION_1_6; } JNIEXPORT void JNICALL @@ -114,9 +119,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS); - //store a handle to this jvm in a global variable - (*env)->GetJavaVM(env, &_jvm); - return LNG(ctx); } diff --git a/src/c/com_freiheit_gnupg_GnuPGContext.h b/src/c/com_freiheit_gnupg_GnuPGContext.h index 6c54f5c..0a2a4d1 100644 --- a/src/c/com_freiheit_gnupg_GnuPGContext.h +++ b/src/c/com_freiheit_gnupg_GnuPGContext.h @@ -7,13 +7,6 @@ #ifdef __cplusplus extern "C" { #endif -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeCheckVersion - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeCheckVersion - (JNIEnv *, jclass); /* * Class: com_freiheit_gnupg_GnuPGContext diff --git a/src/java/com/freiheit/gnupg/GnuPGContext.java b/src/java/com/freiheit/gnupg/GnuPGContext.java index 259c5ff..38250a8 100644 --- a/src/java/com/freiheit/gnupg/GnuPGContext.java +++ b/src/java/com/freiheit/gnupg/GnuPGContext.java @@ -14,11 +14,6 @@ package com.freiheit.gnupg; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; /** Start here, because for all operations, you first need to create a @@ -59,6 +54,11 @@ */ public class GnuPGContext extends GnuPGPeer{ + + static { + System.loadLibrary("gnupg-for-java"); + } + private String _version; private String _filename; private String _reqversion; @@ -495,16 +495,13 @@ public void delete(GnuPGKey key, boolean allowSecret){ GPGME methods. So, if you want to know what these methods are actually doing: Please refer to the GPGME docs. */ - private native static void gpgmeCheckVersion(); private native void gpgmeGetEngineInfo(); private native long gpgmeNew(); private native void gpgmeOpEncrypt(long l, long[] recipientsInternals, long m, long n); private native void gpgmeOpDecrypt(long l, long m, long n); private native void gpgmeOpChangePassphrase(long l, long m ); private native void gpgmeRelease(long l); - @SuppressWarnings("unused") private native void gpgmeOpEncryptSign(long context, int[] recipients, long plain, long cipher); - @SuppressWarnings("unused") private native void gpgmeOpDecryptVerify(long context, long cipher, long plain); private native void gpgmeOpSign(long context, long l, long m); private native void gpgmeOpVerify(long context, long l, long m, long n); @@ -524,124 +521,6 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native long gpgmeGetTextmode(long l); private native void gpgmeSetTextmode(long l, long state); - private static final String NATIVE_LIBRARY_BASENAME = "libgnupg-for-java"; - - /* - It is not possible, to load a shared library directly - from a Jar-Archive. But there is an acceptable workaround: - - Put the shared library in the Jar-Archive - - When the classes get loaded: - - read the shared library from the Jar-Archive - - save it to the standard temp location in the file systems on this platform - - load it from there - - tell java, to automatically get rid of the lib, when the JVM exits (deleteOnExit) - - This way, the library containing the JNI calls must not be installed extra. - It is delivered inside the Jar-Archive, stored temporarily and disappears on exit. - */ - static { - // TODO all this guessing is still rather rough, however it will work - // with most *ix systems and *MAY* work with Windows once we've come - // to test such a setup... - String nativeLibraryExtension = getNativeLibraryExtension(); - - System.out.println("guessed native library extension " + nativeLibraryExtension); - - String libName = getNativeLibraryName(); - - System.out.println("guessed native library name " + libName); - - try{ - InputStream in = GnuPGContext.class.getResource(libName).openStream(); - File tempLib = File.createTempFile(NATIVE_LIBRARY_BASENAME, "." + nativeLibraryExtension); - FileOutputStream out = new FileOutputStream(tempLib); - byte[] buf = new byte[4096]; - for (int i = in.read(buf); i != -1; i = in.read(buf)){ - out.write(buf, 0, i); - } - out.close(); - tempLib.deleteOnExit(); - System.out.println("Trying to load temporary library: " + tempLib.getPath()); - System.load(tempLib.getPath()); - //This call is really important, as it initializes the GPGME thread system!!!! - gpgmeCheckVersion();//FIXME: But: This is NOT working correctly!!! - //---------------------------------------------------------------------------- - } - catch(Throwable e){ - System.out.println("Unable to load shared library from Jar-File."); - System.out.println("Maybe GnuPG for Java is not allowed to write to your disk? (Access problems?)"); - System.out.println("Or the used GnuPG jar-file is not compiled for the current environment/architecture (JavaGnuPG is platform dependent!)."); - System.out.println(e.getMessage()); - e.printStackTrace(); - } - } - - - - /** - * Determines the native library name for the system this is running on. - * If running on unix, we also try to guess the architecture's bit-ness - * which has an impact on the library's name - * @return the name - */ - private static String getNativeLibraryName() { - - // if all fails we assume windblows - String libName = "/c/gnupg-for-java"; - - try { - ProcessBuilder pb = new ProcessBuilder(new String[] { "/bin/uname", "-m" }); - pb.redirectErrorStream(true); - Process p = pb.start(); - InputStreamReader isr = new InputStreamReader(p.getInputStream()); - BufferedReader br = new BufferedReader(isr); - - StringBuilder sb = new StringBuilder(); - String line = null; - - while ((line = br.readLine()) != null) { - //System.out.println(line); - sb.append(line + "\n"); - } - - String uName = sb.toString().trim(); - libName = uName.endsWith("_64") ? "/c/libgnupg-for-java.64" : "/c/libgnupg-for-java.32"; - } catch (Exception e) { - System.err.println("Cannot execute 'uname'. Probably running on a non unix environment."); - /* nothing here, may add some debug output */ - e.printStackTrace(); - } - - return libName + "." + getNativeLibraryExtension(); - } - - /** - * Guesses the native library extension for the system this is running on. - * On unix systems, the extension is "so", on windows it is "dll". - * @return the extension - */ - private static String getNativeLibraryExtension() { - - // try to detect a unix system - File libDir = null; - for (String dirName : new String[] { "/lib", "/usr/lib" }) { - libDir = new File(dirName); - if (libDir.exists() && libDir.isDirectory()) { - String[] found = libDir.list(); - if (found != null && found.length > 0) { - for (String file : found) { - // if we find any file matching lib*.so, we assume unix - if (file.startsWith("lib") && file.endsWith(".so")) { - return "so"; - } - } - } - } - } - - // could not detect a unix system? assume winblows... - return "dll"; - } } /* From 0f5f21dfc2027d632c00198d1389789a0e437992 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 20:43:31 -0400 Subject: [PATCH 04/90] use the libgnupg-for-java.so in place when running the tests --- build.properties | 4 ++-- build.xml | 2 ++ runTests.sh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.properties b/build.properties index 016d361..0c43ff1 100644 --- a/build.properties +++ b/build.properties @@ -2,10 +2,10 @@ app.name=gnupg-for-java app.type=@APP-TYPE@ -app.version=0.1.5-ascii-armor-linux-i386-ia64 +app.version=0.1.6 app.customer=LGPL app.vendor=freiheit.com technologies gmbh -app.year=2008 +app.year=2012 lib=./lib diff --git a/build.xml b/build.xml index d999c00..70fd863 100644 --- a/build.xml +++ b/build.xml @@ -38,6 +38,8 @@ + diff --git a/runTests.sh b/runTests.sh index bd6c1d2..fa4eb1d 100755 --- a/runTests.sh +++ b/runTests.sh @@ -1,4 +1,4 @@ #STYLE=textui STYLE=swingui #STYLE=awtui -java -cp dist/gnupg-for-java-0.1.2-alpha.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.GnuPGTestSuite +java -Djava.library.path=`pwd`/src/c -cp dist/gnupg-for-java-0.1.5.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.GnuPGTestSuite From f7ddc34e94b3b34f233a00ff05f4fcd2a483213d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 20:43:44 -0400 Subject: [PATCH 05/90] ignore dist/ and hs_err_pid*.log --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a267242..2a65bc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ build/ +dist/ +hs_err_pid*.log src/c/*.o src/c/libgnupg-for-java.so From c76f44b87871d70cdbad965dd8bc2fe7da43af04 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 21:09:00 -0400 Subject: [PATCH 06/90] use a standard ant dir structure for JNI stuff: jni/ for source, build/ for products, etc. --- .gitignore | 4 +- build.properties | 9 --- build.xml | 59 +++++++++---------- {src/c => jni}/GNUmakefile | 0 {src/c => jni}/GnuPGContext.c | 0 {src/c => jni}/GnuPGData.c | 0 {src/c => jni}/GnuPGGenkeyResult.c | 0 {src/c => jni}/GnuPGKey.c | 0 {src/c => jni}/GnuPGSignature.c | 0 .../com_freiheit_gnupg_GnuPGContext.h | 0 {src/c => jni}/com_freiheit_gnupg_GnuPGData.h | 0 .../com_freiheit_gnupg_GnuPGGenkeyResult.h | 0 {src/c => jni}/com_freiheit_gnupg_GnuPGKey.h | 0 .../com_freiheit_gnupg_GnuPGSignature.h | 0 {src/c => jni}/gpgmeutils.c | 0 {src/c => jni}/gpgmeutils.h | 0 16 files changed, 31 insertions(+), 41 deletions(-) rename {src/c => jni}/GNUmakefile (100%) rename {src/c => jni}/GnuPGContext.c (100%) rename {src/c => jni}/GnuPGData.c (100%) rename {src/c => jni}/GnuPGGenkeyResult.c (100%) rename {src/c => jni}/GnuPGKey.c (100%) rename {src/c => jni}/GnuPGSignature.c (100%) rename {src/c => jni}/com_freiheit_gnupg_GnuPGContext.h (100%) rename {src/c => jni}/com_freiheit_gnupg_GnuPGData.h (100%) rename {src/c => jni}/com_freiheit_gnupg_GnuPGGenkeyResult.h (100%) rename {src/c => jni}/com_freiheit_gnupg_GnuPGKey.h (100%) rename {src/c => jni}/com_freiheit_gnupg_GnuPGSignature.h (100%) rename {src/c => jni}/gpgmeutils.c (100%) rename {src/c => jni}/gpgmeutils.h (100%) diff --git a/.gitignore b/.gitignore index 2a65bc8..39f2812 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ build/ dist/ hs_err_pid*.log -src/c/*.o -src/c/libgnupg-for-java.so +jni/*.o +jni/libgnupg-for-java.so diff --git a/build.properties b/build.properties index 0c43ff1..4860476 100644 --- a/build.properties +++ b/build.properties @@ -14,14 +14,5 @@ compile.debug=true compile.deprecation=false compile.optimize=true -#where to put the source code -src=src - -#where to put the generated class files -build=build - -#where to put the generated class files -dist=dist - #where to put etc stuff :-) etc=etc diff --git a/build.xml b/build.xml index 70fd863..6d87fcb 100644 --- a/build.xml +++ b/build.xml @@ -1,26 +1,28 @@ + - - + + - - + + - - - + + + + - + - + @@ -33,39 +35,36 @@ - - + + + value="${basedir}/jni"/> - - - - + - + - - - - + + + + - + @@ -76,7 +75,7 @@ - + @@ -87,13 +86,13 @@ - - - - + + + + - - + diff --git a/src/c/GNUmakefile b/jni/GNUmakefile similarity index 100% rename from src/c/GNUmakefile rename to jni/GNUmakefile diff --git a/src/c/GnuPGContext.c b/jni/GnuPGContext.c similarity index 100% rename from src/c/GnuPGContext.c rename to jni/GnuPGContext.c diff --git a/src/c/GnuPGData.c b/jni/GnuPGData.c similarity index 100% rename from src/c/GnuPGData.c rename to jni/GnuPGData.c diff --git a/src/c/GnuPGGenkeyResult.c b/jni/GnuPGGenkeyResult.c similarity index 100% rename from src/c/GnuPGGenkeyResult.c rename to jni/GnuPGGenkeyResult.c diff --git a/src/c/GnuPGKey.c b/jni/GnuPGKey.c similarity index 100% rename from src/c/GnuPGKey.c rename to jni/GnuPGKey.c diff --git a/src/c/GnuPGSignature.c b/jni/GnuPGSignature.c similarity index 100% rename from src/c/GnuPGSignature.c rename to jni/GnuPGSignature.c diff --git a/src/c/com_freiheit_gnupg_GnuPGContext.h b/jni/com_freiheit_gnupg_GnuPGContext.h similarity index 100% rename from src/c/com_freiheit_gnupg_GnuPGContext.h rename to jni/com_freiheit_gnupg_GnuPGContext.h diff --git a/src/c/com_freiheit_gnupg_GnuPGData.h b/jni/com_freiheit_gnupg_GnuPGData.h similarity index 100% rename from src/c/com_freiheit_gnupg_GnuPGData.h rename to jni/com_freiheit_gnupg_GnuPGData.h diff --git a/src/c/com_freiheit_gnupg_GnuPGGenkeyResult.h b/jni/com_freiheit_gnupg_GnuPGGenkeyResult.h similarity index 100% rename from src/c/com_freiheit_gnupg_GnuPGGenkeyResult.h rename to jni/com_freiheit_gnupg_GnuPGGenkeyResult.h diff --git a/src/c/com_freiheit_gnupg_GnuPGKey.h b/jni/com_freiheit_gnupg_GnuPGKey.h similarity index 100% rename from src/c/com_freiheit_gnupg_GnuPGKey.h rename to jni/com_freiheit_gnupg_GnuPGKey.h diff --git a/src/c/com_freiheit_gnupg_GnuPGSignature.h b/jni/com_freiheit_gnupg_GnuPGSignature.h similarity index 100% rename from src/c/com_freiheit_gnupg_GnuPGSignature.h rename to jni/com_freiheit_gnupg_GnuPGSignature.h diff --git a/src/c/gpgmeutils.c b/jni/gpgmeutils.c similarity index 100% rename from src/c/gpgmeutils.c rename to jni/gpgmeutils.c diff --git a/src/c/gpgmeutils.h b/jni/gpgmeutils.h similarity index 100% rename from src/c/gpgmeutils.h rename to jni/gpgmeutils.h From 1fca8e5dd1da3bb412db503e3e8c3205a64cb1bc Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 21:14:31 -0400 Subject: [PATCH 07/90] move .java files straight into src/ --- build.xml | 4 ++-- src/{java => }/com/freiheit/gnupg/GnuPGContext.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGData.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGException.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGGenkeyResult.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGKey.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGPassphraseConsole.java | 0 .../com/freiheit/gnupg/GnuPGPassphraseListener.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGPassphraseWindow.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGPeer.java | 0 src/{java => }/com/freiheit/gnupg/GnuPGSignature.java | 0 src/{java => }/com/freiheit/gnupg/package.html | 0 12 files changed, 2 insertions(+), 2 deletions(-) rename src/{java => }/com/freiheit/gnupg/GnuPGContext.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGData.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGException.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGGenkeyResult.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGKey.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGPassphraseConsole.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGPassphraseListener.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGPassphraseWindow.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGPeer.java (100%) rename src/{java => }/com/freiheit/gnupg/GnuPGSignature.java (100%) rename src/{java => }/com/freiheit/gnupg/package.html (100%) diff --git a/build.xml b/build.xml index 6d87fcb..a858617 100644 --- a/build.xml +++ b/build.xml @@ -14,8 +14,8 @@ - - + + diff --git a/src/java/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGContext.java rename to src/com/freiheit/gnupg/GnuPGContext.java diff --git a/src/java/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGData.java rename to src/com/freiheit/gnupg/GnuPGData.java diff --git a/src/java/com/freiheit/gnupg/GnuPGException.java b/src/com/freiheit/gnupg/GnuPGException.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGException.java rename to src/com/freiheit/gnupg/GnuPGException.java diff --git a/src/java/com/freiheit/gnupg/GnuPGGenkeyResult.java b/src/com/freiheit/gnupg/GnuPGGenkeyResult.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGGenkeyResult.java rename to src/com/freiheit/gnupg/GnuPGGenkeyResult.java diff --git a/src/java/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGKey.java rename to src/com/freiheit/gnupg/GnuPGKey.java diff --git a/src/java/com/freiheit/gnupg/GnuPGPassphraseConsole.java b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGPassphraseConsole.java rename to src/com/freiheit/gnupg/GnuPGPassphraseConsole.java diff --git a/src/java/com/freiheit/gnupg/GnuPGPassphraseListener.java b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGPassphraseListener.java rename to src/com/freiheit/gnupg/GnuPGPassphraseListener.java diff --git a/src/java/com/freiheit/gnupg/GnuPGPassphraseWindow.java b/src/com/freiheit/gnupg/GnuPGPassphraseWindow.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGPassphraseWindow.java rename to src/com/freiheit/gnupg/GnuPGPassphraseWindow.java diff --git a/src/java/com/freiheit/gnupg/GnuPGPeer.java b/src/com/freiheit/gnupg/GnuPGPeer.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGPeer.java rename to src/com/freiheit/gnupg/GnuPGPeer.java diff --git a/src/java/com/freiheit/gnupg/GnuPGSignature.java b/src/com/freiheit/gnupg/GnuPGSignature.java similarity index 100% rename from src/java/com/freiheit/gnupg/GnuPGSignature.java rename to src/com/freiheit/gnupg/GnuPGSignature.java diff --git a/src/java/com/freiheit/gnupg/package.html b/src/com/freiheit/gnupg/package.html similarity index 100% rename from src/java/com/freiheit/gnupg/package.html rename to src/com/freiheit/gnupg/package.html From 56d2ea01150abd6b49fa6e3e462df50a0e3e68bb Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 21:43:03 -0400 Subject: [PATCH 08/90] moved test class into src/ to be built like a regular Java class --- build.xml | 14 +++----------- runTests.sh | 2 +- .../freiheit/gnupg/tests}/GnuPGTestSuite.java | 4 +++- 3 files changed, 7 insertions(+), 13 deletions(-) rename src/{junit/com/freiheit/gnupg => com/freiheit/gnupg/tests}/GnuPGTestSuite.java (99%) diff --git a/build.xml b/build.xml index a858617..697f9f8 100644 --- a/build.xml +++ b/build.xml @@ -19,15 +19,7 @@ - - - - - - - - - + - + diff --git a/runTests.sh b/runTests.sh index fa4eb1d..deb9dec 100755 --- a/runTests.sh +++ b/runTests.sh @@ -1,4 +1,4 @@ #STYLE=textui STYLE=swingui #STYLE=awtui -java -Djava.library.path=`pwd`/src/c -cp dist/gnupg-for-java-0.1.5.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.GnuPGTestSuite +java -Djava.library.path=`pwd`/jni -cp build/jar/gnupg-for-java-0.1.6.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.tests.GnuPGTestSuite diff --git a/src/junit/com/freiheit/gnupg/GnuPGTestSuite.java b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java similarity index 99% rename from src/junit/com/freiheit/gnupg/GnuPGTestSuite.java rename to src/com/freiheit/gnupg/tests/GnuPGTestSuite.java index afeb97d..e2408a0 100644 --- a/src/junit/com/freiheit/gnupg/GnuPGTestSuite.java +++ b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java @@ -11,7 +11,7 @@ * * Please see COPYING for the complete licence. */ -package com.freiheit.gnupg; +package com.freiheit.gnupg.tests; import java.io.File; import java.util.Iterator; @@ -20,6 +20,8 @@ import junit.framework.TestCase; import junit.framework.TestSuite; +import com.freiheit.gnupg.*; + /** I will improve this TestSuite later, that everybody can run it without specific fingerprints. It should behave like the tests in gpgme. From 830244f9e0b6cc5c9529a39a9d73867b43b232c8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 22:41:53 -0400 Subject: [PATCH 09/90] clean up libgnupg-for-java.so build to reflect new layouts and have working dep tracking --- .gitignore | 2 +- build.properties | 3 --- jni/GNUmakefile | 20 +++++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 39f2812..90b27ce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ build/ dist/ hs_err_pid*.log jni/*.o -jni/libgnupg-for-java.so +lib/libgnupg-for-java.so diff --git a/build.properties b/build.properties index 4860476..e8a5dff 100644 --- a/build.properties +++ b/build.properties @@ -1,14 +1,11 @@ # default build.properties app.name=gnupg-for-java -app.type=@APP-TYPE@ app.version=0.1.6 app.customer=LGPL app.vendor=freiheit.com technologies gmbh app.year=2012 -lib=./lib - build.compiler=modern compile.debug=true compile.deprecation=false diff --git a/jni/GNUmakefile b/jni/GNUmakefile index d77aa9c..f7787e2 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -2,7 +2,7 @@ # make JAVA_HOME=/opt/java JAVA_HOME := $(shell readlink -f /usr/bin/javac | sed "s:/bin/javac::") -GNUPG_LIB := libgnupg-for-java.so +GNUPG_LIB := ../lib/libgnupg-for-java.so JNISRC := GnuPGContext.c GnuPGData.c GnuPGGenkeyResult.c GnuPGKey.c GnuPGSignature.c JNI_CLASSES := $(patsubst %.c, com.freiheit.gnupg.%, $(JNISRC)) JNI_HEADERS := $(patsubst %.c, com_freiheit_gnupg_%.h, $(JNISRC)) @@ -22,16 +22,18 @@ CFLAGS := -Werror -Wall -Wno-deprecated-declarations -Wno-unused-but-set-variabl CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -C_IMPL := ./src/c -JAVA_BUILD := ../../build +JAVA_BUILD := ../build/classes LDFLAGS := $(shell gpgme-config --thread=pthread --libs) -lib: $(GNUPG_LIB) - $(GNUPG_LIB): $(OBJECTS) $(CC) $(DEBUG) -shared $(CFLAGS) $^ -o $@ $(LDFLAGS) - $(INSTALL) -m 755 -d $(JAVA_BUILD)/c - $(INSTALL) $(GNUPG_LIB) $(JAVA_BUILD)/c + +$(OBJECTS): $(SOURCES) $(JNI_HEADERS) gpgmeutils.h + +%.o: %.c + $(CC) $(DEBUG) $(CFLAGS) $(CPPFLAGS) -c $< + +lib: $(GNUPG_LIB) header: $(JNI_HEADERS) @@ -52,5 +54,5 @@ test: echo "JNI_HEADERS: $(JNI_HEADERS)" echo "SOURCES: $(SOURCES)" -%.o: %.c $(JNI_HEADERS) gpgmeutils.h - $(CC) $(DEBUG) $(CFLAGS) $(CPPFLAGS) -c $< + +.PHONY: lib header mids clean test From 8169041bb0a14f72ac57e26cd4257890cab12b69 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 23:10:38 -0400 Subject: [PATCH 10/90] make sure the $HOME dir for the tests exists and is empty before running the tests --- build.xml | 2 ++ src/com/freiheit/gnupg/tests/GnuPGTestSuite.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 697f9f8..47d9b08 100644 --- a/build.xml +++ b/build.xml @@ -25,6 +25,8 @@ "swingui" for swing-environment "awtui" for awt-environment --> + + diff --git a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java index e2408a0..583dc25 100644 --- a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java +++ b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java @@ -32,7 +32,7 @@ */ public class GnuPGTestSuite extends TestCase{ - private static String HOME = "/tmp/gnupg"; + private static String HOME = "/tmp/gnupg-for-java-tests"; private static String PLAINTEXT = "I am a not so secret text."; //Currently, you can not run these test without these fingerprints. //And: You need to know the passphrases...forget it. From e4a94d8e2c753a14d00c07aab2560a07e72e803b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 14 Aug 2012 23:17:33 -0400 Subject: [PATCH 11/90] call gpgme_check_version() in JNI_OnLoad() since it seems to set up required things --- jni/GnuPGContext.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 02d6ae8..0cca801 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -81,12 +81,10 @@ JNI_OnLoad(JavaVM *vm, void *reserved) { _jvm = vm; - // TODO set locale from the Java setting + // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); - //FIXME: The tests are hanging, when I use check_version, which is actually - // initializing the threading subsystem...hmmm.. - //char* version = gpgme_check_version (NULL); - //printf("VERSION: %s\n", version); + const char* version = gpgme_check_version(NULL); + fprintf(stderr, "VERSION: %s\n", version); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); From c5d82ac69e3ec817c9d6b03c042cd5136331fb79 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 9 Aug 2012 17:41:18 -0400 Subject: [PATCH 12/90] fix Java warnings in com/freiheit/gnupg --- src/com/freiheit/gnupg/GnuPGData.java | 1 - src/com/freiheit/gnupg/GnuPGKey.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 41ca3a8..0ac9d28 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -139,7 +139,6 @@ protected void finalize(){ private native long gpgmeDataNew(); private native void gpgmeDataWrite(long l, OutputStream out) throws IOException; private native void gpgmeDataRelease(long l); - @SuppressWarnings("unused") private native void gpgmeDataRead(long data, InputStream in) throws IOException; } /* diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 3ef0c49..41518d8 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -99,7 +99,7 @@ be incomplete. This means, that not all details (name, email-address etc.) @see com.freiheit.gnupg.GnuPGSignature */ - public Iterator/**/ getSignatures(){ + public Iterator getSignatures(){ List siglist = null; GnuPGSignature sig = getSignature(); while (sig != null){ @@ -116,7 +116,7 @@ be incomplete. This means, that not all details (name, email-address etc.) Helper to list signatures in the toString()-method. */ private String listSignatures(){ - Iterator iter = getSignatures(); + Iterator iter = getSignatures(); GnuPGSignature sig; StringBuffer buf = new StringBuffer(); From eed4baeb82ae7621503d85bd89ea4c0a62e4cbfe Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 22 Oct 2012 21:54:10 -0400 Subject: [PATCH 13/90] jni: LC_MESSAGES might not be defined on WIN32 or other platforms --- jni/GnuPGContext.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 0cca801..6cf8d9c 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -86,7 +86,9 @@ JNI_OnLoad(JavaVM *vm, void *reserved) const char* version = gpgme_check_version(NULL); fprintf(stderr, "VERSION: %s\n", version); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); +#ifdef LC_MESSAGES gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); +#endif return JNI_VERSION_1_6; } From 8a1bacbf95c464373c76f940f9a748f6f127894a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 22 Oct 2012 23:45:51 -0400 Subject: [PATCH 14/90] gpgme needs LD_LIBRARY_PATH set since it launches cmd line progs like gpg2 gpg2 is dynamically linked, and the only way in Android to find a dylib is via the LD_LIBRARY_PATH. Therefore, the gpg lib dir needs to be added for gpgme env as well. --- jni/GnuPGContext.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 6cf8d9c..484f46c 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -81,10 +81,16 @@ JNI_OnLoad(JavaVM *vm, void *reserved) { _jvm = vm; + // we need to set LD_LIBRARY_PATH because gpgme calls the cmd line utils + const char *ldLibraryPath = getenv("LD_LIBRARY_PATH"); + const char *gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; + size_t newPathLen = strlen(ldLibraryPath) + strlen(gpgAppOpt) + 2; + char newPath[newPathLen]; + snprintf(newPath, newPathLen, "%s:%s", ldLibraryPath, gpgAppOpt); + setenv("LD_LIBRARY_PATH", newPath, 1); // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); const char* version = gpgme_check_version(NULL); - fprintf(stderr, "VERSION: %s\n", version); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); #ifdef LC_MESSAGES gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); From 33d480fad48070e891cb0ade8634a1adf37e507a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 23 Oct 2012 12:51:05 -0400 Subject: [PATCH 15/90] only use LD_LIBRARY_PATH code on Android --- jni/GnuPGContext.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 484f46c..3b06b75 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -81,6 +81,8 @@ JNI_OnLoad(JavaVM *vm, void *reserved) { _jvm = vm; +#ifdef __ANDROID__ + // TODO get the actual gpgAppOpt path from Java // we need to set LD_LIBRARY_PATH because gpgme calls the cmd line utils const char *ldLibraryPath = getenv("LD_LIBRARY_PATH"); const char *gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; @@ -88,6 +90,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) char newPath[newPathLen]; snprintf(newPath, newPathLen, "%s:%s", ldLibraryPath, gpgAppOpt); setenv("LD_LIBRARY_PATH", newPath, 1); +#endif /* __ANDROID */ // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); const char* version = gpgme_check_version(NULL); From 91aed13fba4ab10c88bfe8b641f5405160611b6c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 17:32:38 -0400 Subject: [PATCH 16/90] fix the listkeys feature of the gpgme library --- jni/GnuPGContext.c | 9 +++++++-- src/com/freiheit/gnupg/GnuPGContext.java | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 3b06b75..73d5a4d 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -10,6 +10,10 @@ #include "com_freiheit_gnupg_GnuPGContext.h" #include "gpgmeutils.h" +#include + +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "GnuPGContext", __VA_ARGS__) + JavaVM *_jvm; gpgme_error_t @@ -479,9 +483,10 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, jobject keyObj = NULL; //copy string object from java to native string + const jsize *query_len = (*env)->GetStringLength(env, query); + LOGD("query length %d\n", (int) query_len); const jbyte *query_str = (jbyte *)(*env)->GetStringUTFChars(env, query, NULL); - //get the right constructor to invoke for every key in result set jclass keyClass; keyClass = (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGKey"); @@ -502,7 +507,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, int j = 0; //index in result array, used only in second loop run... for (i = 0; i < 2; i++) { //loops [0..1] err = gpgme_op_keylist_start(CONTEXT(context), - (const char *)query_str, + (int)query_len > 0 ? (const char *)query_str : NULL, 0); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, query, (const char *)query_str); diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 38250a8..9f0a147 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -274,6 +274,17 @@ public GnuPGKey[] generateEmptyKeyArray(int withLengthOf){ } } + /** + List all keys in keyring. + + @return GnuPGKey array of key objects with all keys + + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey[] listKeys() throws GnuPGException{ + return searchKeys(""); + } + /** Find all keys matching query in keyring. @@ -283,11 +294,10 @@ public GnuPGKey[] generateEmptyKeyArray(int withLengthOf){ @see com.freiheit.gnupg.GnuPGKey */ public GnuPGKey[] searchKeys(String query) throws GnuPGException{ - if (query == null || query.length() < 1) { - return null; - } else{ - return gpgmeKeylist(getInternalRepresentation(), query); + if (query == null ) { + query = new String(""); } + return gpgmeKeylist(getInternalRepresentation(), query); } /** From 694cb36692957a86c3207b4de332dd30c1638249 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 23 May 2013 20:16:45 -0400 Subject: [PATCH 17/90] gnupg-for-java: expose all booleans in gpgme_key_t as Java methods --- jni/GnuPGKey.c | 71 +++++++++++++++++++++++++++- src/com/freiheit/gnupg/GnuPGKey.java | 51 ++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index b8e6bcc..5946740 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -81,7 +81,6 @@ Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetUserID(JNIEnv * env, jobject self, return str; } - JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetSignature(JNIEnv * env, jobject self, jlong key) @@ -89,6 +88,76 @@ Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetSignature(JNIEnv * env, jobject self, return LNG((KEY(key))->uids->signatures); } +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanEncrypt(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->can_encrypt; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanSign(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->can_sign; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanCerify(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->can_certify; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanAuthenticate(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->can_authenticate; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsRevoked(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->revoked; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsExpired(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->expired; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsDisabled(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->disabled; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsInvalid(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->invalid; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsQualified(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->is_qualified; +} + +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsSecret(JNIEnv * env, jobject self, + jlong key) +{ + return (KEY(key))->secret; +} + /* void */ /* setMembers(JNIEnv *env, jobject self, gpgme_key_t key){ */ /* jclass cls = (*env)->GetObjectClass(env, self); */ diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 41518d8..e654f23 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -83,6 +83,46 @@ public String getUserID(){ return gpgmeGetUserID(getInternalRepresentation()); } + public boolean canEncrypt() { + return gpgmeCanEncrypt(getInternalRepresentation()); + } + + public boolean canSign() { + return gpgmeCanSign(getInternalRepresentation()); + } + + public boolean canCertify() { + return gpgmeCanCertify(getInternalRepresentation()); + } + + public boolean canAuthenticate() { + return gpgmeCanAuthenticate(getInternalRepresentation()); + } + + public boolean isRevoked() { + return gpgmeIsRevoked(getInternalRepresentation()); + } + + public boolean isExpired() { + return gpgmeIsExpired(getInternalRepresentation()); + } + + public boolean isDisabled() { + return gpgmeIsDisabled(getInternalRepresentation()); + } + + public boolean isInvalid() { + return gpgmeIsInvalid(getInternalRepresentation()); + } + + public boolean isQualified() { + return gpgmeIsQualified(getInternalRepresentation()); + } + + public boolean isSecret() { + return gpgmeIsSecret(getInternalRepresentation()); + } + /** Lists all signatures of the default key/userid. Every key can have multiple signatures. Signatures can @@ -197,6 +237,17 @@ protected void finalize(){ private native String gpgmeGetComment(long keyptr); private native String gpgmeGetUserID(long keyptr); private native long gpgmeGetSignature(long keyptr); + private native boolean gpgmeCanEncrypt(long keyptr); + private native boolean gpgmeCanSign(long keyptr); + private native boolean gpgmeCanCertify(long keyptr); + private native boolean gpgmeCanAuthenticate(long keyptr); + private native boolean gpgmeIsRevoked(long keyptr); + private native boolean gpgmeIsExpired(long keyptr); + private native boolean gpgmeIsDisabled(long keyptr); + private native boolean gpgmeIsInvalid(long keyptr); + private native boolean gpgmeIsQualified(long keyptr); + private native boolean gpgmeIsSecret(long keyptr); + } /* * Local variables: From 2148509e7cdeff6554bfc7dbaf31fe2212535a04 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 11:11:13 -0400 Subject: [PATCH 18/90] remove unneeded autogenerated JNI headers I think this are only used for C++, but right now they are just another file to maintain while providing no benefit to us. They can be updated in the gnupg-for-java project once development settles down. --- jni/GnuPGContext.c | 2 +- jni/GnuPGData.c | 2 +- jni/GnuPGGenkeyResult.c | 2 +- jni/GnuPGKey.c | 2 +- jni/GnuPGSignature.c | 2 +- jni/com_freiheit_gnupg_GnuPGContext.h | 198 --------------------- jni/com_freiheit_gnupg_GnuPGData.h | 53 ------ jni/com_freiheit_gnupg_GnuPGGenkeyResult.h | 13 -- jni/com_freiheit_gnupg_GnuPGKey.h | 85 --------- jni/com_freiheit_gnupg_GnuPGSignature.h | 93 ---------- 10 files changed, 5 insertions(+), 447 deletions(-) delete mode 100644 jni/com_freiheit_gnupg_GnuPGContext.h delete mode 100644 jni/com_freiheit_gnupg_GnuPGData.h delete mode 100644 jni/com_freiheit_gnupg_GnuPGGenkeyResult.h delete mode 100644 jni/com_freiheit_gnupg_GnuPGKey.h delete mode 100644 jni/com_freiheit_gnupg_GnuPGSignature.h diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 73d5a4d..b88880e 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -7,7 +7,7 @@ #include #include -#include "com_freiheit_gnupg_GnuPGContext.h" + #include "gpgmeutils.h" #include diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 0d61ee3..cf83d41 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -1,7 +1,7 @@ #include #include -#include "com_freiheit_gnupg_GnuPGData.h" + #include "gpgmeutils.h" #include diff --git a/jni/GnuPGGenkeyResult.c b/jni/GnuPGGenkeyResult.c index 4e71a96..6bcf72a 100644 --- a/jni/GnuPGGenkeyResult.c +++ b/jni/GnuPGGenkeyResult.c @@ -1,6 +1,6 @@ #include #include -#include "com_freiheit_gnupg_GnuPGGenkeyResult.h" + #include "gpgmeutils.h" #include diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index 5946740..c6f5ad9 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -1,6 +1,6 @@ #include #include -#include "com_freiheit_gnupg_GnuPGKey.h" + #include "gpgmeutils.h" #include diff --git a/jni/GnuPGSignature.c b/jni/GnuPGSignature.c index ef63479..3ca7a9d 100644 --- a/jni/GnuPGSignature.c +++ b/jni/GnuPGSignature.c @@ -1,6 +1,6 @@ #include #include -#include "com_freiheit_gnupg_GnuPGSignature.h" + #include "gpgmeutils.h" #include diff --git a/jni/com_freiheit_gnupg_GnuPGContext.h b/jni/com_freiheit_gnupg_GnuPGContext.h deleted file mode 100644 index 0a2a4d1..0000000 --- a/jni/com_freiheit_gnupg_GnuPGContext.h +++ /dev/null @@ -1,198 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freiheit_gnupg_GnuPGContext */ - -#ifndef _Included_com_freiheit_gnupg_GnuPGContext -#define _Included_com_freiheit_gnupg_GnuPGContext -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeGetEngineInfo - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo - (JNIEnv *, jobject); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeNew - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew - (JNIEnv *, jobject); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpEncrypt - * Signature: (J[JJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt - (JNIEnv *, jobject, jlong, jlongArray, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpDecrypt - * Signature: (JJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt - (JNIEnv *, jobject, jlong, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpChangePassphrase - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeRelease - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeRelease - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpEncryptSign - * Signature: (J[IJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign - (JNIEnv *, jobject, jlong, jintArray, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpDecryptVerify - * Signature: (JJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify - (JNIEnv *, jobject, jlong, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpSign - * Signature: (JJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign - (JNIEnv *, jobject, jlong, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpVerify - * Signature: (JJJJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify - (JNIEnv *, jobject, jlong, jlong, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeKeylist - * Signature: (JLjava/lang/String;)[Lcom/freiheit/gnupg/GnuPGKey; - */ -JNIEXPORT jobjectArray JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist - (JNIEnv *, jobject, jlong, jstring); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeAddSigners - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeClearSigners - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeClearSigners - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpImport - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpExport - * Signature: (JLjava/lang/String;JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport - (JNIEnv *, jobject, jlong, jstring, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpGenKey - * Signature: (JLjava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey - (JNIEnv *, jobject, jlong, jstring); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeCtxSetEngineInfo - * Signature: (JILjava/lang/String;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo - (JNIEnv *, jobject, jlong, jint, jstring, jstring); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpGenkeyResult - * Signature: (J)Lcom/freiheit/gnupg/GnuPGGenkeyResult; - */ -JNIEXPORT jobject JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeOpDelete - * Signature: (JJZ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete - (JNIEnv *, jobject, jlong, jlong, jboolean); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeGetArmor - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetArmor - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeSetArmor - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetArmor - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeGetTextmode - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetTextmode - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGContext - * Method: gpgmeSetTextmode - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetTextmode - (JNIEnv *, jobject, jlong, jlong); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/jni/com_freiheit_gnupg_GnuPGData.h b/jni/com_freiheit_gnupg_GnuPGData.h deleted file mode 100644 index 3245048..0000000 --- a/jni/com_freiheit_gnupg_GnuPGData.h +++ /dev/null @@ -1,53 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freiheit_gnupg_GnuPGData */ - -#ifndef _Included_com_freiheit_gnupg_GnuPGData -#define _Included_com_freiheit_gnupg_GnuPGData -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_freiheit_gnupg_GnuPGData - * Method: gpgmeDataNewFromMem - * Signature: ([B)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem - (JNIEnv *, jobject, jbyteArray); - -/* - * Class: com_freiheit_gnupg_GnuPGData - * Method: gpgmeDataNew - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNew - (JNIEnv *, jobject); - -/* - * Class: com_freiheit_gnupg_GnuPGData - * Method: gpgmeDataWrite - * Signature: (JLjava/io/OutputStream;)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataWrite - (JNIEnv *, jobject, jlong, jobject); - -/* - * Class: com_freiheit_gnupg_GnuPGData - * Method: gpgmeDataRelease - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRelease - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGData - * Method: gpgmeDataRead - * Signature: (JLjava/io/InputStream;)V - */ -JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead - (JNIEnv *, jobject, jlong, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/jni/com_freiheit_gnupg_GnuPGGenkeyResult.h b/jni/com_freiheit_gnupg_GnuPGGenkeyResult.h deleted file mode 100644 index f7297a2..0000000 --- a/jni/com_freiheit_gnupg_GnuPGGenkeyResult.h +++ /dev/null @@ -1,13 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freiheit_gnupg_GnuPGGenkeyResult */ - -#ifndef _Included_com_freiheit_gnupg_GnuPGGenkeyResult -#define _Included_com_freiheit_gnupg_GnuPGGenkeyResult -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif -#endif diff --git a/jni/com_freiheit_gnupg_GnuPGKey.h b/jni/com_freiheit_gnupg_GnuPGKey.h deleted file mode 100644 index 793eae3..0000000 --- a/jni/com_freiheit_gnupg_GnuPGKey.h +++ /dev/null @@ -1,85 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freiheit_gnupg_GnuPGKey */ - -#ifndef _Included_com_freiheit_gnupg_GnuPGKey -#define _Included_com_freiheit_gnupg_GnuPGKey -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetKey - * Signature: (JLjava/lang/String;)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKey - (JNIEnv *, jobject, jlong, jstring); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeKeyUnref - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeKeyUnref - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetName - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetName - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetEmail - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetEmail - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetKeyID - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKeyID - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetFingerprint - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetFingerprint - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetComment - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetComment - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetUserID - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetUserID - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGKey - * Method: gpgmeGetSignature - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetSignature - (JNIEnv *, jobject, jlong); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/jni/com_freiheit_gnupg_GnuPGSignature.h b/jni/com_freiheit_gnupg_GnuPGSignature.h deleted file mode 100644 index e5fe53e..0000000 --- a/jni/com_freiheit_gnupg_GnuPGSignature.h +++ /dev/null @@ -1,93 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freiheit_gnupg_GnuPGSignature */ - -#ifndef _Included_com_freiheit_gnupg_GnuPGSignature -#define _Included_com_freiheit_gnupg_GnuPGSignature -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetRevoked - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetRevoked - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetExpired - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExpired - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetInvalid - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetInvalid - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetExportable - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExportable - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetKeyID - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetKeyID - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetUserID - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetUserID - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetName - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetName - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetEmail - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetEmail - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetComment - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetComment - (JNIEnv *, jobject, jlong); - -/* - * Class: com_freiheit_gnupg_GnuPGSignature - * Method: gpgmeGetNextSignature - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetNextSignature - (JNIEnv *, jobject, jlong); - -#ifdef __cplusplus -} -#endif -#endif From f90f6cfeb704ffd0b44598b1d5562b05ea75bd26 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 11:55:03 -0400 Subject: [PATCH 19/90] gnupg-for-java: add GnuPGKey.hasSecretKey() to report if any subkey is secret --- jni/GnuPGKey.c | 12 ++++++++++++ src/com/freiheit/gnupg/GnuPGKey.java | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index c6f5ad9..7072a00 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -158,6 +158,18 @@ Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsSecret(JNIEnv * env, jobject self, return (KEY(key))->secret; } +JNIEXPORT jboolean JNICALL +Java_com_freiheit_gnupg_GnuPGKey_gpgmeHasSecretKey(JNIEnv * env, jobject self, + jlong key) +{ + jboolean hasSecretKey = 0; + gpgme_subkey_t subkey; + for(subkey = KEY(key)->subkeys; subkey; subkey = subkey->next) + if (subkey->secret) + return 1; + return 0; +} + /* void */ /* setMembers(JNIEnv *env, jobject self, gpgme_key_t key){ */ /* jclass cls = (*env)->GetObjectClass(env, self); */ diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index e654f23..faa5d9c 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -123,6 +123,10 @@ public boolean isSecret() { return gpgmeIsSecret(getInternalRepresentation()); } + public boolean hasSecretKey() { + return gpgmeHasSecretKey(getInternalRepresentation()); + } + /** Lists all signatures of the default key/userid. Every key can have multiple signatures. Signatures can @@ -247,6 +251,7 @@ protected void finalize(){ private native boolean gpgmeIsInvalid(long keyptr); private native boolean gpgmeIsQualified(long keyptr); private native boolean gpgmeIsSecret(long keyptr); + private native boolean gpgmeHasSecretKey(long keyptr); } /* From 0c208a32449e5d2ba1aaad0967d81f83ef91e29a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 12:45:09 -0400 Subject: [PATCH 20/90] gnupg-for-java: fix compiler warnings --- jni/GnuPGContext.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index b88880e..c52e6d3 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,7 @@ passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, } JNIEnv *env; - (*_jvm)->AttachCurrentThread(_jvm, (void **) &env, NULL); + (*_jvm)->AttachCurrentThread(_jvm, &env, NULL); jclass cls = (*env)->GetObjectClass(env, self); @@ -483,8 +484,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, jobject keyObj = NULL; //copy string object from java to native string - const jsize *query_len = (*env)->GetStringLength(env, query); - LOGD("query length %d\n", (int) query_len); + const jsize query_len = (*env)->GetStringLength(env, query); + LOGD("query length %d\n", query_len); const jbyte *query_str = (jbyte *)(*env)->GetStringUTFChars(env, query, NULL); //get the right constructor to invoke for every key in result set @@ -507,7 +508,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, int j = 0; //index in result array, used only in second loop run... for (i = 0; i < 2; i++) { //loops [0..1] err = gpgme_op_keylist_start(CONTEXT(context), - (int)query_len > 0 ? (const char *)query_str : NULL, + query_len > 0 ? (const char *)query_str : NULL, 0); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, query, (const char *)query_str); From 4afc03e1e1ce71c9cf48486c41c448e208f66980 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 18:43:21 -0400 Subject: [PATCH 21/90] gnupg-for-java: also allow fetching secret keys using GnuPGKey contructor Before, it would only search and return public keys --- jni/GnuPGKey.c | 5 +++-- src/com/freiheit/gnupg/GnuPGKey.java | 23 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index 7072a00..08cb09a 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -8,12 +8,13 @@ JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKey(JNIEnv * env, jobject self, - jlong context, jstring fingerprint) + jlong context, jstring fingerprint, + jboolean secret) { gpgme_key_t key; const char *fpr = (*env)->GetStringUTFChars(env, fingerprint, NULL); - gpgme_error_t err = gpgme_get_key(CONTEXT(context), fpr, &key, 0); + gpgme_error_t err = gpgme_get_key(CONTEXT(context), fpr, &key, secret); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, fingerprint, fpr); return LNG(NULL); diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index faa5d9c..60393a3 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -37,8 +37,25 @@ protected GnuPGKey(long ptr) { setInternalRepresentation(ptr); } - protected GnuPGKey(GnuPGContext context, String fingerprint){ - setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint)); + /** + * Fetch a public key by its 16 hex char fingerprint String + * + * @param context - the current GnuPGContext + * @param fingerprint - the 16 hex char fingerprint String + */ + protected GnuPGKey(GnuPGContext context, String fingerprint) { + setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, false)); + } + + /** + * Fetch a key by its 16 hex char fingerprint String + * + * @param context the current GnuPGContext + * @param fingerprint the 16 hex char fingerprint String + * @param secret_only whether to return only secret keys + */ + protected GnuPGKey(GnuPGContext context, String fingerprint, boolean secret_only) { + setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, secret_only)); } /** @@ -232,7 +249,7 @@ protected void finalize(){ destroy(); } - private native long gpgmeGetKey(long context, String fingerprint); + private native long gpgmeGetKey(long context, String fingerprint, boolean secret); private native long gpgmeKeyUnref(long keyptr); private native String gpgmeGetName(long keyptr); private native String gpgmeGetEmail(long keyptr); From cbfe16ae0b07732eb2d68871b816bee572d8b34a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 19:33:44 -0400 Subject: [PATCH 22/90] allow fetching secret keys using GnuPGContext.getKeyByFingerprint() --- src/com/freiheit/gnupg/GnuPGContext.java | 30 +++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 9f0a147..f9ece13 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -196,21 +196,39 @@ private boolean hasNoRecipients(GnuPGKey[] recipients){ } /** - Gets the key with the supplied fingerprint from the keyring. + Gets the public key with the supplied fingerprint from the keyring. This is also kind of a factory method to generate key objects, because you always need a context to access the keys in your keyring. - @param fingerprint gpg fingerprint (must be in your keyring) - @return GnuPGKey the key with the matching fingerprint + @param fingerprint 16 char hex fingerprint of key in your keyring + @return GnuPGKey the public key that matches the fingerprint @see com.freiheit.gnupg.GnuPGKey */ - public GnuPGKey getKeyByFingerprint(String fingerprint) throws GnuPGException{ + public GnuPGKey getKeyByFingerprint(String fingerprint) throws GnuPGException { if(fingerprint == null || fingerprint.length() < 1) { return null; + } else { + return new GnuPGKey(this, fingerprint, false); } - else{ - return new GnuPGKey(this, fingerprint); + } + + /** + Gets the secret key with the supplied fingerprint from the keyring. + This is also kind of a factory method to generate secret key objects, + because you always need a context to access the keys in your keyring. + + @param fingerprint 16 char hex fingerprint of key in your keyring + @return GnuPGKey the secret key that matches the fingerprint + + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey getSecretKeyByFingerprint(String fingerprint) + throws GnuPGException { + if(fingerprint == null || fingerprint.length() < 1) { + return null; + } else { + return new GnuPGKey(this, fingerprint, true); } } From 05e35c782ac1cc4aaadc37bdb401ae3bc96c98a3 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 19:41:13 -0400 Subject: [PATCH 23/90] add listSecretKeys() and searchSecretKeys() to GnuPGContext --- jni/GnuPGContext.c | 5 ++-- src/com/freiheit/gnupg/GnuPGContext.java | 36 ++++++++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index c52e6d3..3f0a712 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -475,7 +475,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv * env, jobject self, JNIEXPORT jobjectArray JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, - jlong context, jstring query) + jlong context, jstring query, + jboolean secret_only) { gpgme_error_t err; gpgme_key_t key; @@ -509,7 +510,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, for (i = 0; i < 2; i++) { //loops [0..1] err = gpgme_op_keylist_start(CONTEXT(context), query_len > 0 ? (const char *)query_str : NULL, - 0); + secret_only); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, query, (const char *)query_str); return NULL; diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index f9ece13..3d49f7b 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -293,9 +293,9 @@ public GnuPGKey[] generateEmptyKeyArray(int withLengthOf){ } /** - List all keys in keyring. + List all public keys in keyring. - @return GnuPGKey array of key objects with all keys + @return GnuPGKey array of key objects with all public keys @see com.freiheit.gnupg.GnuPGKey */ @@ -303,8 +303,19 @@ public GnuPGKey[] listKeys() throws GnuPGException{ return searchKeys(""); } + /** + List all secret keys in keyring. + + @return GnuPGKey array of key objects with all secret keys + + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey[] listSecretKeys() throws GnuPGException{ + return searchSecretKeys(""); + } + /** - Find all keys matching query in keyring. + Find all public keys matching query in keyring. @param query allows the same expressions as gpg on command line @return GnuPGKey array of key objects with all matching keys @@ -315,7 +326,22 @@ public GnuPGKey[] searchKeys(String query) throws GnuPGException{ if (query == null ) { query = new String(""); } - return gpgmeKeylist(getInternalRepresentation(), query); + return gpgmeKeylist(getInternalRepresentation(), query, false); + } + + /** + Find all keys matching query in keyring. + + @param query allows the same expressions as gpg on command line + @return GnuPGKey array of key objects with all matching keys + + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey[] searchSecretKeys(String query) throws GnuPGException{ + if (query == null ) { + query = new String(""); + } + return gpgmeKeylist(getInternalRepresentation(), query, true); } /** @@ -533,7 +559,7 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native void gpgmeOpDecryptVerify(long context, long cipher, long plain); private native void gpgmeOpSign(long context, long l, long m); private native void gpgmeOpVerify(long context, long l, long m, long n); - private native GnuPGKey[] gpgmeKeylist(long l, String query); + private native GnuPGKey[] gpgmeKeylist(long l, String query, boolean secret_only); private native void gpgmeAddSigners(long l, long m); private native void gpgmeClearSigners(long context); private native void gpgmeOpImport(long context, long l); From eb3d09466247dd6fb099f17f1af1358832be65ee Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 24 May 2013 22:42:16 -0400 Subject: [PATCH 24/90] simplify and complete get/set for Armor and TextMode --- src/com/freiheit/gnupg/GnuPGContext.java | 39 ++++++++++++------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 3d49f7b..aacf1bf 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -114,8 +114,7 @@ public int getProtocol(){ @return boolean true if results will be ASCII armored, if false binary */ public boolean isArmor(){ - long armorState = gpgmeGetArmor(getInternalRepresentation()); - return (armorState == 1); + return gpgmeGetArmor(getInternalRepresentation()); } /** @@ -125,9 +124,8 @@ public boolean isArmor(){ @param state set true if results should be ASCII armored, set false if binary */ - public void setArmor(boolean state){ - long armorState = (state ? 1 : 0); - gpgmeSetArmor(getInternalRepresentation(), armorState); + public void setArmor(boolean state) { + gpgmeSetArmor(getInternalRepresentation(), state); } /** @@ -136,24 +134,27 @@ public void setArmor(boolean state){ @return boolean true means text mode is on */ - public boolean isTextmode(){ - boolean result = false; - long mode = gpgmeGetTextmode(getInternalRepresentation()); - if(mode == 1){ - result = true; - } - return result; + public boolean isTextmode() { + return gpgmeGetTextmode(getInternalRepresentation()); } + /** + Get the current text mode from the gpg engine. + Please check GPG/GPGME for documentation if you don't know what this means. + + @return boolean if textmode is currently enabled + */ + public boolean getTextmode(){ + return gpgmeGetTextmode(getInternalRepresentation()); + } /** Tell the gpg engine to set the text mode. Please check GPG/GPGME for documentation if you don't know what this means. @param state set true if you want text mode switched on */ - public void setTextmode(boolean state){ - long mode = (state ? 1 : 0); - gpgmeSetTextmode(getInternalRepresentation(), mode); + public void setTextmode(boolean state) { + gpgmeSetTextmode(getInternalRepresentation(), state); } /** @@ -570,10 +571,10 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native void gpgmeOpDelete(long context, long l, boolean allowSecret); //getters/setters for members, no caching, always direct access to gpgme - private native long gpgmeGetArmor(long l); - private native void gpgmeSetArmor(long l, long state); - private native long gpgmeGetTextmode(long l); - private native void gpgmeSetTextmode(long l, long state); + private native boolean gpgmeGetArmor(long l); + private native void gpgmeSetArmor(long l, boolean state); + private native boolean gpgmeGetTextmode(long l); + private native void gpgmeSetTextmode(long l, boolean state); } From 1c912a1b333968f6f4314cae2e7516e4703d306e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 25 May 2013 12:39:28 -0400 Subject: [PATCH 25/90] add GnuPGData.size() to improve ByteArrayOutputStream performance Since ByteArrayOutputStreams are used to get data out of GnuPGData, add a size() method so that the ByteArrayOutputStream can pre-allocate the memory needed, or at least close to the final number. --- jni/GnuPGData.c | 8 ++++++++ src/com/freiheit/gnupg/GnuPGData.java | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index cf83d41..143e546 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -5,9 +5,17 @@ #include "gpgmeutils.h" #include +#include #define BUFSIZE 1024 + +JNIEXPORT jsize JNICALL +Java_com_freiheit_gnupg_GnuPGData_gpgmeSize(JNIEnv * env, jobject self, jlong data) +{ + return (jsize) (DATA(data))->data.mem.size; +} + JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem(JNIEnv * env, jobject self, diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 0ac9d28..7e58c60 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -99,11 +99,11 @@ public void write(OutputStream out) throws IOException{ /** Helper method to print out the data/string from this data object. - @return String representation of the data contained in this data object (expect weired results with binary data) + @return String representation of the data contained in this data object (expect weird results with binary data) */ public String toString(){ String result = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(this.size()); try{ this.write(baos); result = baos.toString(); @@ -135,6 +135,11 @@ protected void finalize(){ destroy(); } + public int size() { + return gpgmeSize(getInternalRepresentation()); + } + + private native int gpgmeSize(long l); private native long gpgmeDataNewFromMem(byte[] plain); private native long gpgmeDataNew(); private native void gpgmeDataWrite(long l, OutputStream out) throws IOException; From a163416a690cd6a4ffc1397b34cc01fedc21cdb4 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 25 May 2013 11:05:36 -0400 Subject: [PATCH 26/90] add javaish encryption methods --- src/com/freiheit/gnupg/GnuPGContext.java | 183 +++++++++++++++++++++-- 1 file changed, 172 insertions(+), 11 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index aacf1bf..f118702 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -14,6 +14,9 @@ package com.freiheit.gnupg; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; /** Start here, because for all operations, you first need to create a @@ -346,23 +349,181 @@ public GnuPGKey[] searchSecretKeys(String query) throws GnuPGException{ } /** - Encrypts the data from plain with the public key - of each recipient. The result is stored in cipher. + * Encrypt plain text and return ASCII-armored text. + * + * @param recipients array of keys to encrypt to + * @param plain the plain text to be encrypted + * @return String encrypted data in ASCII-armored text + */ + public String encryptToAscii(GnuPGKey[] recipients, String plain) { + final GnuPGData plainData = createDataObject(plain); + final String ret = encryptToAscii(recipients, plainData); + plainData.destroy(); + return ret; + } + + /** + * Encrypt a byte array and return ASCII-armored text. + * + * @param recipients array of keys to encrypt to + * @param plain the byte[] to be encrypted + * @return String encrypted data in ASCII-armored text + */ + public String encryptToAscii(GnuPGKey[] recipients, byte[] plain) { + final GnuPGData plainData = createDataObject(plain); + final String ret = encryptToAscii(recipients, plainData); + plainData.destroy(); + return ret; + } + + /** + * Encrypt plain text and return ASCII-armored text. + * + * @param recipients array of keys to encrypt to + * @param plain the GnuPGData to be encrypted + * @return String encrypted data in ASCII-armored text + */ + public String encryptToAscii(GnuPGKey[] recipients, GnuPGData plain) { + long l = getInternalRepresentation(); + boolean previous = gpgmeGetArmor(l); + gpgmeSetArmor(l, true); + GnuPGData cipher = createDataObject(); + encrypt(recipients, plain, cipher); + final String ret = cipher.toString(); + cipher.destroy(); + if (previous == false) // maintain the original ASCII-Armor state + gpgmeSetArmor(l, false); + return ret; + } + + /** + * Encrypt a byte array and return encrypted data in binary form. + * + * @param recipients array of keys to encrypt to + * @param plain the plain binary data to be encrypted + * @return byte[] encrypted data in binary data + */ + public byte[] encryptToBinary(GnuPGKey[] recipients, byte[] plain) { + final GnuPGData plainData = createDataObject(plain); + final byte[] ret = encryptToBinary(recipients, plainData); + plainData.destroy(); + return ret; + } - @param recipients Array with the public keys of all recipients - @param plain text, that should be encrypted - @param cipher text, the encrypted plain text after method call + /** + * Encrypt plain text and return encrypted data in binary form. + * + * @param recipients array of keys to encrypt to + * @param plain the plain text to be encrypted + * @return byte[] encrypted data in binary data + */ + public byte[] encryptToBinary(GnuPGKey[] recipients, String plain) { + final GnuPGData plainData = createDataObject(plain); + final byte[] ret = encryptToBinary(recipients, plainData); + plainData.destroy(); + return ret; + } + + /** + * Encrypt plain data and return encrypted data in binary form. + * + * @param recipients array of keys to encrypt to + * @param plain the GnuPGData to be encrypted + * @return String encrypted data in ASCII-armored text + */ + public byte[] encryptToBinary(GnuPGKey[] recipients, GnuPGData plain) { + long l = getInternalRepresentation(); + boolean previous = gpgmeGetArmor(l); + gpgmeSetArmor(l, true); + GnuPGData cipher = createDataObject(); + encrypt(recipients, plain, cipher); + ByteArrayOutputStream baos = new ByteArrayOutputStream(plain.size()); + BufferedOutputStream out = new BufferedOutputStream(baos, 8192); + try { + cipher.write(out); + } catch (IOException e) { + e.printStackTrace(); + } + cipher.destroy(); + if (previous == false) // maintain the original ASCII-Armor state + gpgmeSetArmor(l, false); + return baos.toByteArray(); + } + + /** + Encrypts the text in plain with the public key + of each recipient. The result is returned as GnuPGData. + + @param recipients array of the keys to encrypt to + @param plain bytes to be encrypted + @return GnuPGData the encrypted data @see com.freiheit.gnupg.GnuPGData @see com.freiheit.gnupg.GnuPGKey */ - public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException{ - if (hasNoRecipients(recipients) || plain == null || cipher == null) throw new GnuPGException("Encryption-Arguments not complete."); + public GnuPGData encrypt(GnuPGKey[] recipients, byte[] plain) + throws GnuPGException{ + if (hasNoRecipients(recipients) || plain == null || plain.length == 0) + throw new GnuPGException("Encryption arguments not complete."); - // note that these are pointers to addresses in the gnupg-for-java shared lib - long recipientsInternals[] = getInternalRepresentationFromRecipients(recipients); - gpgmeOpEncrypt(this.getInternalRepresentation(), recipientsInternals, - plain.getInternalRepresentation(), cipher.getInternalRepresentation()); + final GnuPGData plainData = createDataObject(plain); + GnuPGData cipherData = createDataObject(); + + gpgmeOpEncrypt(this.getInternalRepresentation(), + getInternalRepresentationFromRecipients(recipients), + plainData.getInternalRepresentation(), + cipherData.getInternalRepresentation()); + plainData.destroy(); + return cipherData; + } + + /** + Encrypts the text in plain with the public key + of each recipient. The result is returned as GnuPGData. + + @param recipients array of the keys to encrypt to + @param plain the text to be encrypted + @return GnuPGData the encrypted data + + @see com.freiheit.gnupg.GnuPGData + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGData encrypt(GnuPGKey[] recipients, String plain) + throws GnuPGException{ + if (hasNoRecipients(recipients) || plain == null || plain.equals("")) + throw new GnuPGException("Encryption arguments not complete."); + + final GnuPGData plainData = createDataObject(plain); + GnuPGData cipherData = createDataObject(); + + gpgmeOpEncrypt(this.getInternalRepresentation(), + getInternalRepresentationFromRecipients(recipients), + plainData.getInternalRepresentation(), + cipherData.getInternalRepresentation()); + plainData.destroy(); + return cipherData; + } + + /** + Encrypts the data from plain with the public key + of each recipient. The result is stored in cipher. + + @param recipients Array with the public keys of all recipients + @param plain text, that should be encrypted + @param cipher text, the encrypted plain text after method call + + @see com.freiheit.gnupg.GnuPGData + @see com.freiheit.gnupg.GnuPGKey + */ + public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException{ + if (hasNoRecipients(recipients) || plain == null || cipher == null) + throw new GnuPGException("Encryption arguments not complete."); + + // note that these are pointers to addresses in the gnupg-for-java shared lib + gpgmeOpEncrypt(this.getInternalRepresentation(), + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); } /* From 07d843fff83ff10ef198d36ad30129142bf4dae3 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 18:25:08 -0400 Subject: [PATCH 27/90] sync up trivial changes from gnupg-for-android --- src/com/freiheit/gnupg/GnuPGContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index f118702..800fa64 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -18,6 +18,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; + /** Start here, because for all operations, you first need to create a GnuPGContext. Use one context object for every single thread or @@ -57,7 +58,7 @@ */ public class GnuPGContext extends GnuPGPeer{ - + public static final String TAG = "GnuPGContext"; static { System.loadLibrary("gnupg-for-java"); } From 0d512652b63fcb7dc4b27f9348b7552c8df783af Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 25 May 2013 15:16:15 -0400 Subject: [PATCH 28/90] include signature notations in key lists --- jni/GnuPGContext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 3f0a712..fb1a7bc 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -131,7 +131,9 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) gpgme_set_armor(ctx, 1); gpgme_set_textmode(ctx, 1); gpgme_set_keylist_mode(ctx, - GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS); + GPGME_KEYLIST_MODE_LOCAL \ + | GPGME_KEYLIST_MODE_SIGS \ + | GPGME_KEYLIST_MODE_SIG_NOTATIONS); return LNG(ctx); } From f17ef6eaf49d4be890b03f1adba0a5b2233e3a37 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 31 May 2013 18:23:05 -0400 Subject: [PATCH 29/90] put gnupg libs first in LD_LIBRARY_PATH to make sure we get the right ones this should make it a tiny bit harder to sneak a bad .so into gnupg, and also avoid cases where people might install stuff willy-nilly on their device. --- jni/GnuPGContext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index fb1a7bc..3a860ca 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -93,7 +93,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) const char *gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; size_t newPathLen = strlen(ldLibraryPath) + strlen(gpgAppOpt) + 2; char newPath[newPathLen]; - snprintf(newPath, newPathLen, "%s:%s", ldLibraryPath, gpgAppOpt); + snprintf(newPath, newPathLen, "%s:%s", gpgAppOpt, ldLibraryPath); setenv("LD_LIBRARY_PATH", newPath, 1); #endif /* __ANDROID */ // TODO set locale from the JavaVM's config From 1f8856601a3a2b570f987319d8afafbe4b3f6a18 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 16:00:38 -0400 Subject: [PATCH 30/90] standardize layout of public method declarations for clarity I want to be able to rapidly scan the methods and see how the args differ. --- jni/GnuPGContext.c | 151 ++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 65 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 3a860ca..0755659 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -108,8 +108,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo(JNIEnv * env, - jobject self) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo(JNIEnv * env, jobject self) { gpgme_engine_info_t engineInfo; gpgme_get_engine_info(&engineInfo); @@ -139,10 +138,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, jobject self, - jlong context, - jlongArray recipients, - jlong plain, jlong cipher) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, + jobject self, + jlong context, + jlongArray recipients, + jlong plain, + jlong cipher) { gpgme_error_t err; @@ -189,9 +190,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, jobject self, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv * env, jobject self, - jlong context, jlong cipher, - jlong plain) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv * env, + jobject self, + jlong context, + jlong cipher, + jlong plain) { gpgme_error_t err; @@ -278,9 +281,9 @@ edit_fnc(void *opaque, gpgme_status_code_t status, const char *args, int fd) JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv * env, - jobject self, - jlong context, - jlong keydata) + jobject self, + jlong context, + jlong keydata) { gpgme_error_t err; @@ -314,19 +317,20 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv * env, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeRelease(JNIEnv * env, jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeRelease(JNIEnv * env, + jobject self, + jlong context) { gpgme_release(CONTEXT(context)); } JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv * env, - jobject self, - jlong context, - jlongArray recipients, - jlong plain, - jlong cipher) + jobject self, + jlong context, + jlongArray recipients, + jlong plain, + jlong cipher) { gpgme_error_t err; @@ -366,10 +370,10 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv * env, JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv * env, - jobject self, - jlong context, - jlong cipher, - jlong plain) + jobject self, + jlong context, + jlong cipher, + jlong plain) { gpgme_error_t err; @@ -400,9 +404,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv * env, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv * env, jobject self, - jlong context, jlong plain, - jlong signature) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv * env, + jobject self, + jlong context, + jlong plain, + jlong signature) { gpgme_error_t err; @@ -436,10 +442,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv * env, jobject self, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv * env, jobject self, - jlong context, - jlong signature, - jlong signedtxt, jlong plain) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv * env, + jobject self, + jlong context, + jlong signature, + jlong signedtxt, + jlong plain) { gpgme_error_t err; @@ -476,8 +484,10 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv * env, jobject self, } JNIEXPORT jobjectArray JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, - jlong context, jstring query, +Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, + jobject self, + jlong context, + jstring query, jboolean secret_only) { gpgme_error_t err; @@ -553,8 +563,10 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, jobject self, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners(JNIEnv * env, jobject self, - jlong context, jlong key) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners(JNIEnv * env, + jobject self, + jlong context, + jlong key) { gpgme_error_t err; err = gpgme_signers_add(CONTEXT(context), KEY(key)); @@ -565,8 +577,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners(JNIEnv * env, jobject self, JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeClearSigners(JNIEnv * env, - jobject self, - jlong context) + jobject self, + jlong context) { gpgme_signers_clear(CONTEXT(context)); } @@ -699,8 +711,10 @@ void check_result(gpgme_import_result_t result, char *fpr, int secret) } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv * env, jobject self, - jlong context, jlong keydata) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv * env, + jobject self, + jlong context, + jlong keydata) { gpgme_error_t err; gpgme_import_result_t result; @@ -740,40 +754,44 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv * env, jobject self, } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetArmor(JNIEnv * env, jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetArmor(JNIEnv * env, + jobject self, + jlong context) { return (jlong) gpgme_get_armor(CONTEXT(context)); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetArmor(JNIEnv * env, jobject self, - jlong context, - jlong armor_state) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetArmor(JNIEnv * env, + jobject self, + jlong context, + jlong armor_state) { gpgme_set_armor(CONTEXT(context), (int) armor_state); } JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetTextmode(JNIEnv * env, - jobject self, - jlong context) + jobject self, + jlong context) { return (jlong) gpgme_get_textmode(CONTEXT(context)); } JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetTextmode(JNIEnv * env, - jobject self, - jlong context, jlong mode) + jobject self, + jlong context, + jlong mode) { gpgme_set_textmode(CONTEXT(context), (int) mode); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv * env, jobject self, - jlong context, - jstring params) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv * env, + jobject self, + jlong context, + jstring params) { gpgme_ctx_t ctx = CONTEXT(context); @@ -796,11 +814,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv * env, jobject self, JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv * env, jobject self, - jlong context, - jstring pattern, - jlong reserved, - jlong keydata) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv * env, + jobject self, + jlong context, + jstring pattern, + jlong reserved, + jlong keydata) { gpgme_ctx_t ctx = CONTEXT(context); @@ -819,11 +838,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv * env, jobject self, JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv * env, - jobject self, - jlong ctx, - jint proto, - jstring fileName, - jstring homeDir) + jobject self, + jlong ctx, + jint proto, + jstring fileName, + jstring homeDir) { gpgme_ctx_t context = CONTEXT(ctx); @@ -851,8 +870,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv * env, JNIEXPORT jobject JNICALL Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult(JNIEnv * env, - jobject self, - jlong ctx) + jobject self, + jlong ctx) { gpgme_ctx_t context = CONTEXT(ctx); @@ -888,9 +907,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult(JNIEnv * env, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv * env, jobject self, - jlong ctx, jlong key, - jboolean allowSecret) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv * env, + jobject self, + jlong ctx, + jlong key, + jboolean allowSecret) { gpgme_ctx_t context = CONTEXT(ctx); From 8b7c761ea538cfb335d7f1671e95be5f660d24f1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 16:05:57 -0400 Subject: [PATCH 31/90] fix gpgmeOpEncryptSign method signature in Java --- src/com/freiheit/gnupg/GnuPGContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 800fa64..e300299 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -718,7 +718,7 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native void gpgmeOpDecrypt(long l, long m, long n); private native void gpgmeOpChangePassphrase(long l, long m ); private native void gpgmeRelease(long l); - private native void gpgmeOpEncryptSign(long context, int[] recipients, long plain, long cipher); + private native void gpgmeOpEncryptSign(long context, long[] recipients, long plain, long cipher); private native void gpgmeOpDecryptVerify(long context, long cipher, long plain); private native void gpgmeOpSign(long context, long l, long m); private native void gpgmeOpVerify(long context, long l, long m, long n); From 351d29d539102bd26d5e531a554060ed6215046b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 17:35:16 -0400 Subject: [PATCH 32/90] implement getSigner() and getSignersLength() context.h comes from gpgme, but it is really meant to be an internal header, so we should not be using it. This should be replaced by the new API function in gpgme that does the same thing. https://dev.guardianproject.info/issues/1549 --- jni/GnuPGContext.c | 19 +++++++++++++++++ src/com/freiheit/gnupg/GnuPGContext.java | 26 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 0755659..74d6738 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "gpgmeutils.h" @@ -583,6 +584,24 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeClearSigners(JNIEnv * env, gpgme_signers_clear(CONTEXT(context)); } +JNIEXPORT jlong JNICALL +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSigner(JNIEnv * env, + jobject self, + jlong context, + jint index) +{ + gpgme_key_t key = gpgme_signers_enum(CONTEXT(context), index); + return LNG(key); +} + +JNIEXPORT jlong JNICALL +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSignersLength(JNIEnv * env, + jobject self, + jlong context) +{ + return (CONTEXT(context)->signers_len); +} + void check_result(gpgme_import_result_t result, char *fpr, int secret) { //TODO: Throw exception for possible errors... diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index e300299..67518c1 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -631,6 +631,30 @@ public void clearSigners() throws GnuPGException{ gpgmeClearSigners(getInternalRepresentation()); } + /** + Get a specific Signer at a given index. You add Signers + with addSigner(). + + @param int index to the list of Signers + @return GnuPGKey the key at index, or null if it doesn't exist + + @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey getSigner(int index) throws GnuPGException { + return new GnuPGKey(gpgmeGetSigner(getInternalRepresentation(), index)); + } + + /** + Gets the number of Signers currently in the GnuPGContext. You add Signers + with addSigner(). + @return long the number of Signers currently in the GnuPGContext + + @see com.freiheit.gnupg.GnuPGKey + */ + public long getSignersLength() throws GnuPGException { + return gpgmeGetSignersLength(getInternalRepresentation()); + } + /** Imports a Key (private or public). You can supply the key in ASCII armor. */ @@ -725,6 +749,8 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native GnuPGKey[] gpgmeKeylist(long l, String query, boolean secret_only); private native void gpgmeAddSigners(long l, long m); private native void gpgmeClearSigners(long context); + private native long gpgmeGetSigner(long context, int index); + private native long gpgmeGetSignersLength(long context); private native void gpgmeOpImport(long context, long l); private native void gpgmeOpExport(long context, String pattern, long reserved, long l); private native void gpgmeOpGenKey(long context,String params); From 473e0c6203d7a3ba4e9cc22f7036759e187695f5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 17:52:08 -0400 Subject: [PATCH 33/90] add encryptAndSign method to force signing with encryption --- src/com/freiheit/gnupg/GnuPGContext.java | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 67518c1..f590905 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -527,17 +527,15 @@ public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) th cipher.getInternalRepresentation()); } - /* - Not finished. - */ -// public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException{ -// if (hasNoRecipients(recipients) || plain == null || cipher == null) throw new GnuPGException("Encryption-Arguments not complete."); - -// long recipientsInternals[] = getInternalRepresentationFromRecipients(recipients); - -// gpgmeOpEncryptSign(this.getInternalRepresentation(), recipientsInternals, -// plain.getInternalRepresentation(), cipher.getInternalRepresentation()); -// } + public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException { + if (hasNoRecipients(recipients) || plain == null || cipher == null) + throw new GnuPGException("Encryption-Arguments not complete."); + + gpgmeOpEncryptSign(this.getInternalRepresentation(), + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); + } /** Decrypts the data from cipher and stores the result From f0478e20becd0f73d42ab8fa8c7bad91d8eeb64e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 17:53:46 -0400 Subject: [PATCH 34/90] make encrypt() do signing if GnuPGContext has signers added --- src/com/freiheit/gnupg/GnuPGContext.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index f590905..fcb0b52 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -521,10 +521,17 @@ public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) th throw new GnuPGException("Encryption arguments not complete."); // note that these are pointers to addresses in the gnupg-for-java shared lib - gpgmeOpEncrypt(this.getInternalRepresentation(), - getInternalRepresentationFromRecipients(recipients), - plain.getInternalRepresentation(), - cipher.getInternalRepresentation()); + long context = this.getInternalRepresentation(); + if (gpgmeGetSignersLength(context) == 0) + gpgmeOpEncrypt(context, + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); + else + gpgmeOpEncryptSign(context, + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); } public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException { From 987e168cbb612b8fc95231009e6d95828d3ea9e1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Jun 2013 19:36:33 -0400 Subject: [PATCH 35/90] add simple method for generating a new PGP key --- src/com/freiheit/gnupg/GnuPGContext.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index fcb0b52..c149c88 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -688,6 +688,13 @@ protected void finalize(){ destroy(); } + /** + * Generates a new PGP key and stores it in the keyring. + */ + public void genPgpKey(String params) throws GnuPGException { + gpgmeOpGenKey(getInternalRepresentation(),params); + } + /** Generates a new Key. */ From 69b4153c45a5cc18c8fe9df44ed5717257c9a289 Mon Sep 17 00:00:00 2001 From: Abel Luck Date: Fri, 14 Jun 2013 19:48:38 +0200 Subject: [PATCH 36/90] implement key importing from a file in gnupg-for-java --- src/com/freiheit/gnupg/GnuPGContext.java | 36 +++++++++++++++++++--- src/com/freiheit/gnupg/GnuPGData.java | 39 +++++++++++++----------- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index c149c88..41f142e 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -14,8 +14,11 @@ package com.freiheit.gnupg; +import android.util.Log; + import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; @@ -237,6 +240,21 @@ public GnuPGKey getSecretKeyByFingerprint(String fingerprint) } } + /** + * Factory method to generate a GnuPGData-Object from a File. + * + * @param data should not be null be readable + * @return GnuPGData null is data is null or empty, otherwise a + * GnuPGData-Object + * @throws IOException + */ + public GnuPGData createDataObject(File f) throws GnuPGException, IOException { + if(f != null && f.exists() && !f.isDirectory() && f.canRead()){ + return new GnuPGData(f); + } + return null; + } + /** Factory method to generate a GnuPGData-Object from a String. @@ -450,7 +468,7 @@ public byte[] encryptToBinary(GnuPGKey[] recipients, GnuPGData plain) { gpgmeSetArmor(l, false); return baos.toByteArray(); } - + /** Encrypts the text in plain with the public key of each recipient. The result is returned as GnuPGData. @@ -469,7 +487,7 @@ public GnuPGData encrypt(GnuPGKey[] recipients, byte[] plain) final GnuPGData plainData = createDataObject(plain); GnuPGData cipherData = createDataObject(); - + gpgmeOpEncrypt(this.getInternalRepresentation(), getInternalRepresentationFromRecipients(recipients), plainData.getInternalRepresentation(), @@ -496,7 +514,7 @@ public GnuPGData encrypt(GnuPGKey[] recipients, String plain) final GnuPGData plainData = createDataObject(plain); GnuPGData cipherData = createDataObject(); - + gpgmeOpEncrypt(this.getInternalRepresentation(), getInternalRepresentationFromRecipients(recipients), plainData.getInternalRepresentation(), @@ -639,7 +657,7 @@ public void clearSigners() throws GnuPGException{ /** Get a specific Signer at a given index. You add Signers with addSigner(). - + @param int index to the list of Signers @return GnuPGKey the key at index, or null if it doesn't exist @@ -667,6 +685,15 @@ public void importKey(GnuPGData keydata) throws GnuPGException{ gpgmeOpImport(getInternalRepresentation(), keydata.getInternalRepresentation()); } + /** + * Imports a Key (private or public). You can supply the key in ASCII armor. + */ + public void importKey(File file) throws GnuPGException, IOException { + GnuPGData keydata = createDataObject(file); + if( keydata == null ) { Log.e(TAG, "importkey: parsing key data failed" ); return; } + gpgmeOpImport(getInternalRepresentation(), keydata.getInternalRepresentation()); + } + /** This calls immediately the release method for the context in the underlying gpgme library. This method is called by @@ -684,6 +711,7 @@ public void destroy(){ /** Releases underlying datastructures. Simple calls the destroy() method. */ + @Override protected void finalize(){ destroy(); } diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 7e58c60..c99f7bf 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -14,7 +14,10 @@ package com.freiheit.gnupg; +import org.apache.commons.io.FileUtils; + import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -38,18 +41,18 @@ protected GnuPGData(){ setInternalRepresentation(gpgmeDataNew()); } - /* - Use the factory methods from GnuPGContext to - generate GnuPGData-Objects. - FIXME: This is not working! Use it, and it will crash the JVM. - */ -// public GnuPGData(File f) throws IOException{ -// this(); -// if(f != null && f.exists() && !f.isDirectory() && f.canRead()){ -// FileInputStream fin = new FileInputStream(f); -// this.read(fin); -// } -// } + + /** + Use the factory methods from GnuPGContext to + generate GnuPGData-Objects. + Generates a new data object containing the contents of the given File. + + @param f your file + @throws IOException + */ + public GnuPGData(File f) throws IOException { + this(FileUtils.readFileToByteArray(f)); + } /** Use the factory methods from GnuPGContext to @@ -78,11 +81,11 @@ protected GnuPGData(byte[] data){ /* FIXME: This is not working! Use it, and it will crash the JVM. */ -// public void read(InputStream in) throws IOException{ -// if(in != null){ -// gpgmeDataRead(getInternalRepresentation(), in); -// } -// } + public void read(InputStream in) throws IOException{ + if(in != null){ + gpgmeDataRead(getInternalRepresentation(), in); + } + } /** Writes the data/string contained in this data object @@ -101,6 +104,7 @@ public void write(OutputStream out) throws IOException{ @return String representation of the data contained in this data object (expect weird results with binary data) */ + @Override public String toString(){ String result = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(this.size()); @@ -131,6 +135,7 @@ public void destroy(){ /** Releases underlying datastructures. Simple calls the destroy() method. */ + @Override protected void finalize(){ destroy(); } From 1fe5bf8b8044cec2430ed4ea823cd3b382cb6579 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Jun 2013 21:17:53 -0400 Subject: [PATCH 37/90] disable gpgme passphraseListener, use pinentry on gpg 2.x --- jni/GnuPGContext.c | 4 ++++ src/com/freiheit/gnupg/GnuPGContext.java | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 74d6738..8b34bbe 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -18,6 +18,9 @@ JavaVM *_jvm; +void* passphrase_cb = NULL; + +/* gpgme_error_t passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd) @@ -81,6 +84,7 @@ passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, return GPG_ERR_NO_ERROR; } +*/ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 41f142e..556a863 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -572,7 +572,6 @@ public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cip @see com.freiheit.gnupg.GnuPGData */ public void decrypt(GnuPGData cipher, GnuPGData plain) throws GnuPGException{ - if(_passphraseListener == null) throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); if (cipher == null || plain == null) return; gpgmeOpDecrypt(this.getInternalRepresentation(), @@ -597,7 +596,6 @@ public void changePassphrase( GnuPGKey key ) throws GnuPGException { @param plain will contain the result after the method call */ // public void decryptAndVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGException{ -// if(_passphraseListener == null) throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); // if (cipher == null || plain == null) return; // gpgmeOpDecryptVerify(this.getInternalRepresentation(), @@ -611,7 +609,6 @@ public void changePassphrase( GnuPGKey key ) throws GnuPGException { @param signature result of the operation */ public void sign(GnuPGData plain, GnuPGData signature) throws GnuPGException{ - if(_passphraseListener == null) throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); if (plain == null || signature == null) throw new GnuPGException("Parameters not complete or null."); gpgmeOpSign(this.getInternalRepresentation(), From 7f842086c4956a8ed5d55e242b162325618a64fa Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 12 Jul 2013 14:24:52 -0400 Subject: [PATCH 38/90] use POSIX FILE streams when creating GnuPGData for files Previously, GnuPGData(File f) would load the entire contents of the file into memory, then pass a memory gpgme_data_t to gpgme. This is horrible when working with large files or machines with limited memory. This patch uses the gpgme function for creating a gpgme_data_t from a POSIX FILE stream. --- jni/GnuPGData.c | 32 ++++++++++++++++- src/com/freiheit/gnupg/GnuPGData.java | 50 +++++++++++++++++---------- 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 143e546..6e5190a 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -44,6 +44,33 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem(JNIEnv * env, return result; } +JNIEXPORT jlong JNICALL +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromFilename(JNIEnv * env, + jobject self, + jstring filename, + jstring mode) +{ + const char *mode_str = (*env)->GetStringUTFChars(env, mode, NULL); + const char *filename_str = (*env)->GetStringUTFChars(env, filename, NULL); + if (filename_str == NULL) { + fprintf(stderr, "could not allocate memory.\n"); + return 0; + } + + gpgme_data_t data; + FILE* stream = fopen(filename_str, mode_str); + gpgme_error_t err = gpgme_data_new_from_stream(&data, stream); + if (UTILS_onErrorThrowException(env, err)) { + return LNG(NULL); + } + + (*env)->ReleaseStringUTFChars(env, filename, filename_str); + (*env)->ReleaseStringUTFChars(env, mode, mode_str); + + jlong result = LNG(data); + return result; +} + JNIEXPORT jlong JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNew(JNIEnv * env, jobject self) { @@ -110,7 +137,10 @@ JNIEXPORT void JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRelease(JNIEnv * env, jobject self, jlong data) { - gpgme_data_release(DATA(data)); + gpgme_data_t dh = DATA(data); + if (dh->data.stream != NULL) + fclose(dh->data.stream); + gpgme_data_release(dh); } JNIEXPORT void JNICALL diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index c99f7bf..5ab5a78 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -14,10 +14,9 @@ package com.freiheit.gnupg; -import org.apache.commons.io.FileUtils; - import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -31,8 +30,7 @@ public class GnuPGData extends GnuPGPeer{ /** - Use the factory methods from GnuPGContext to - generate GnuPGData-Objects. + Use the factory methods from GnuPGContext to create GnuPGData instances. Generates an empty data object. Use this, if you want to create a data object to hold a result from a crypto operation. @@ -41,22 +39,38 @@ protected GnuPGData(){ setInternalRepresentation(gpgmeDataNew()); } + /** + * Use the factory methods in GnuPGContext to create GnuPGData instances. + * Generates a new data object based on read/write stream access to a file. + * + * @param file your file + * @throws IOException + */ + protected GnuPGData(File file) throws IOException, GnuPGException { + this(file, "r+"); + } /** - Use the factory methods from GnuPGContext to - generate GnuPGData-Objects. - Generates a new data object containing the contents of the given File. - - @param f your file - @throws IOException - */ - public GnuPGData(File f) throws IOException { - this(FileUtils.readFileToByteArray(f)); - } + * Use the factory methods in GnuPGContext to create GnuPGData instances. + * Generates a new data object based on stream access to a file, with + * settable open mode. + * + * @param file your file + * @param mode the POSIX mode to open the file, e.g "r" or "w+" + * @throws IOException + */ + protected GnuPGData(File file, String mode) throws IOException, GnuPGException { + if (file == null || !file.exists()) + throw new FileNotFoundException(); + if (!file.canRead()) + throw new IOException("Cannot read: " + file); + if (!file.canRead()) + throw new IOException("Is a directory: " + file); + setInternalRepresentation(gpgmeDataNewFromFilename(file.getCanonicalPath(), mode)); + } /** - Use the factory methods from GnuPGContext to - generate GnuPGData-Objects. + Use the factory methods from GnuPGContext to create GnuPGData instances. Generates a new data object containing the given String. @param str your string @@ -66,8 +80,7 @@ protected GnuPGData(String str){ } /** - Use the factory methods from GnuPGContext to - generate GnuPGData-Objects. + Use the factory methods from GnuPGContext to create GnuPGData instances. Generates a new Data-Object containing the given byte array. @param data your data @@ -146,6 +159,7 @@ public int size() { private native int gpgmeSize(long l); private native long gpgmeDataNewFromMem(byte[] plain); + private native long gpgmeDataNewFromFilename(String filename, String mode); private native long gpgmeDataNew(); private native void gpgmeDataWrite(long l, OutputStream out) throws IOException; private native void gpgmeDataRelease(long l); From 841967352636fe0a4938c20fd2f4b4cfb372b37a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 15 Jul 2013 20:57:03 -0400 Subject: [PATCH 39/90] expose gpgmeOpDecryptVerify as a proper Java method Currently this will throw an Exception if the verify fails. We need to implement gpgme_verify_result_t in Java, like GnuPGGenKeyResult.java in order to get useful information about the verification process. refs #1567 --- src/com/freiheit/gnupg/GnuPGContext.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 556a863..3cf9473 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -154,6 +154,7 @@ public boolean isTextmode() { public boolean getTextmode(){ return gpgmeGetTextmode(getInternalRepresentation()); } + /** Tell the gpg engine to set the text mode. Please check GPG/GPGME for documentation if you don't know what this means. @@ -578,6 +579,24 @@ public void decrypt(GnuPGData cipher, GnuPGData plain) throws GnuPGException{ cipher.getInternalRepresentation(), plain.getInternalRepresentation()); } + /** + * Decrypts the data from cipher and stores the result in + * plain, then verifies the signature of the data. If the + * decryption or verification fails, it throws a GnuPGException. + * + * @param cipher holds the data to be decrypted and verified + * @param plain holds the decrypted data after decryption + * @see com.freiheit.gnupg.GnuPGData + */ + public void decryptVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGException { + if (cipher == null || plain == null) + return; + + gpgmeOpDecryptVerify(this.getInternalRepresentation(), + cipher.getInternalRepresentation(), + plain.getInternalRepresentation()); + } + public void changePassphrase( GnuPGKey key ) throws GnuPGException { if(_passphraseListener == null) throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); From 52f19f7ed9eb10eeb61850a2b1d467c7c23bfc97 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 19 Jul 2013 19:05:30 -0400 Subject: [PATCH 40/90] reduce the keylist return to the bare minimum for speed This makes the keylist functions return much less information, so hopefully it will speed things up. There should be an option for getting the full info when its needed. refs #1621 --- jni/GnuPGContext.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 8b34bbe..9de2336 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -134,10 +134,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) gpgme_new(&ctx); gpgme_set_armor(ctx, 1); gpgme_set_textmode(ctx, 1); - gpgme_set_keylist_mode(ctx, - GPGME_KEYLIST_MODE_LOCAL \ - | GPGME_KEYLIST_MODE_SIGS \ - | GPGME_KEYLIST_MODE_SIG_NOTATIONS); + gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL); return LNG(ctx); } From 4d85b13a5aa4be957fcdfe9df1eaa446d0c4b8d8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 29 Jul 2013 11:52:33 -0400 Subject: [PATCH 41/90] purge emacs code format comment, use the emacs 'java' mode Emacs now has a built-in Java mode for its code formatter, use that instead of the comment to describe the code format. Also, Eclipse's code formatter messes up the emacs code format comment block anyway. refs #1629 --- src/com/freiheit/gnupg/GnuPGContext.java | 8 -------- src/com/freiheit/gnupg/GnuPGData.java | 7 ------- src/com/freiheit/gnupg/GnuPGException.java | 7 ------- src/com/freiheit/gnupg/GnuPGKey.java | 7 ------- src/com/freiheit/gnupg/GnuPGPassphraseConsole.java | 7 ------- src/com/freiheit/gnupg/GnuPGPassphraseListener.java | 7 ------- src/com/freiheit/gnupg/GnuPGPeer.java | 7 ------- src/com/freiheit/gnupg/GnuPGSignature.java | 8 -------- 8 files changed, 58 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 3cf9473..9ab50a1 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -821,11 +821,3 @@ public void delete(GnuPGKey key, boolean allowSecret){ private native void gpgmeSetTextmode(long l, boolean state); } - -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 5ab5a78..237f128 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -165,10 +165,3 @@ public int size() { private native void gpgmeDataRelease(long l); private native void gpgmeDataRead(long data, InputStream in) throws IOException; } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGException.java b/src/com/freiheit/gnupg/GnuPGException.java index 3f3a60f..9ef68a3 100644 --- a/src/com/freiheit/gnupg/GnuPGException.java +++ b/src/com/freiheit/gnupg/GnuPGException.java @@ -34,10 +34,3 @@ public class GnuPGException extends RuntimeException{ super(msg); } } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 60393a3..447398c 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -271,10 +271,3 @@ protected void finalize(){ private native boolean gpgmeHasSecretKey(long keyptr); } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java index bc6fd11..52ef56c 100644 --- a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java +++ b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java @@ -55,10 +55,3 @@ public String getPassphrase(String hint, String passphraseInfo, long wasBad){ return line; } } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java index 1fe9f77..994315f 100644 --- a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java +++ b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java @@ -43,10 +43,3 @@ public interface GnuPGPassphraseListener{ */ public String getPassphrase(String hint, String passphraseInfo, long wasBad); } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGPeer.java b/src/com/freiheit/gnupg/GnuPGPeer.java index bac2cc2..2e2331a 100644 --- a/src/com/freiheit/gnupg/GnuPGPeer.java +++ b/src/com/freiheit/gnupg/GnuPGPeer.java @@ -40,10 +40,3 @@ protected long getInternalRepresentation(){ return _internalRepresentation; } } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/GnuPGSignature.java b/src/com/freiheit/gnupg/GnuPGSignature.java index e3c295a..d989d06 100644 --- a/src/com/freiheit/gnupg/GnuPGSignature.java +++ b/src/com/freiheit/gnupg/GnuPGSignature.java @@ -187,11 +187,3 @@ protected GnuPGSignature getNextSignature(){ private native long gpgmeGetNextSignature(long l); } - -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ From 29ac3464b01995468ce41b3a9d6b9cba661f8e61 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 29 Jul 2013 12:14:58 -0400 Subject: [PATCH 42/90] ran Eclipse code formatter in Android mode on *.java refs #1629 --- src/com/freiheit/gnupg/GnuPGContext.java | 874 +++++++++--------- src/com/freiheit/gnupg/GnuPGData.java | 104 ++- src/com/freiheit/gnupg/GnuPGException.java | 20 +- src/com/freiheit/gnupg/GnuPGGenkeyResult.java | 52 +- src/com/freiheit/gnupg/GnuPGKey.java | 183 ++-- .../gnupg/GnuPGPassphraseConsole.java | 33 +- .../gnupg/GnuPGPassphraseListener.java | 44 +- src/com/freiheit/gnupg/GnuPGPeer.java | 25 +- src/com/freiheit/gnupg/GnuPGSignature.java | 154 +-- 9 files changed, 778 insertions(+), 711 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 9ab50a1..f9732b1 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -14,54 +14,58 @@ package com.freiheit.gnupg; -import android.util.Log; - import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import android.util.Log; /** - Start here, because for all operations, you first need to create a - GnuPGContext. Use one context object for every single thread or - (really) take care about synchronizing access to the context from - different threads. -

- How to create a context? -

-   {@code
-     GnuPGContext ctx = new GnuPGContext();
-   }
-   
- If you execute an operation, where GnuPG needs a passphrase - (password, mantra) from you, you need to tell the - library which Class is listening for such a request and is able to - deliver the entered passphrase to the library. You can implement - such a listener by yourself, but you can also use two - pre-fabricated ones. (Of course, normally you should install - gpg-agent/pinentry for this job...but some will need this ability - to get passphrases from a database or so. And: This release is not - checking for the existence of gpg-agent...so it won't work anyway.) -

- How to add a Passphrase-Listener to read a password from the console? -

-   {@code
-     ctx.setPassphraseListener(new GnuPGPassphraseConsole());
-     //caution: you can still see the password while you are typing...
-   }
-   
- How to add a Passphrase-Listener to read a password from the swing dialog? -
-   {@code
-     ctx.setPassphraseListener(new GnuPGPassphraseWindow());
-   }
-   
- @author Stefan Richter, stefan@freiheit.com + * Start here, because for all operations, you first need to create a + * GnuPGContext. Use one context object for every single thread or (really) take + * care about synchronizing access to the context from different threads. + *

+ * How to create a context? + * + *

+ * {
+ *     @code
+ *     GnuPGContext ctx = new GnuPGContext();
+ * }
+ * 
+ * + * If you execute an operation, where GnuPG needs a passphrase (password, + * mantra) from you, you need to tell the library which Class is listening for + * such a request and is able to deliver the entered passphrase to the library. + * You can implement such a listener by yourself, but you can also use two + * pre-fabricated ones. (Of course, normally you should install + * gpg-agent/pinentry for this job...but some will need this ability to get + * passphrases from a database or so. And: This release is not checking for the + * existence of gpg-agent...so it won't work anyway.) + *

+ * How to add a Passphrase-Listener to read a password from the console? + * + *

+ *    {@code
+ *      ctx.setPassphraseListener(new GnuPGPassphraseConsole());
+ *      //caution: you can still see the password while you are typing...
+ *    }
+ * 
+ * + * How to add a Passphrase-Listener to read a password from the swing dialog? + * + *
+ *    {@code
+ *      ctx.setPassphraseListener(new GnuPGPassphraseWindow());
+ *    }
+ * 
+ * + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGContext extends GnuPGPeer{ - public static final String TAG = "GnuPGContext"; +public class GnuPGContext extends GnuPGPeer { + public static final String TAG = "GnuPGContext"; static { System.loadLibrary("gnupg-for-java"); } @@ -72,126 +76,128 @@ public class GnuPGContext extends GnuPGPeer{ private int _protocol; private GnuPGPassphraseListener _passphraseListener = null; - /** Creates a new Context (use on context for one thread!)*/ - public GnuPGContext(){ + /** Creates a new Context (use on context for one thread!) */ + public GnuPGContext() { gpgmeGetEngineInfo(); setInternalRepresentation(gpgmeNew()); } /** - Returns the version of the underlying GPGME lib version. - @return library version as String (like "1.1.1") - */ - public String getVersion(){ + * Returns the version of the underlying GPGME lib version. + * + * @return library version as String (like "1.1.1") + */ + public String getVersion() { return _version; } /** - Returns the executable gpg with path - @return gpg executable as String (like "/usr/bin/gpg") + * Returns the executable gpg with path + * + * @return gpg executable as String (like "/usr/bin/gpg") */ - public String getFilename(){ + public String getFilename() { return _filename; } - /** - Returns the required version of the underlying GPGME lib. - - @return required library version as String (like "1.1.1") - */ - public String getRequiredVersion(){ + * Returns the required version of the underlying GPGME lib. + * + * @return required library version as String (like "1.1.1") + */ + public String getRequiredVersion() { return _reqversion; } /** - Returns the used protocol of the crypto backend. - - @return protocol - */ - public int getProtocol(){ + * Returns the used protocol of the crypto backend. + * + * @return protocol + */ + public int getProtocol() { return _protocol; } /** - Tells you, is the gpg engine uses ASCII armor. - Please check GPG/GPGME for documentation if you don't know what this means. - (Try 'man gpg' on the command line and look for 'armor') - - @return boolean true if results will be ASCII armored, if false binary + * Tells you, is the gpg engine uses ASCII armor. Please check GPG/GPGME for + * documentation if you don't know what this means. (Try 'man gpg' on the + * command line and look for 'armor') + * + * @return boolean true if results will be ASCII armored, if false binary */ - public boolean isArmor(){ + public boolean isArmor() { return gpgmeGetArmor(getInternalRepresentation()); } /** - Tell the gpg engine to use ASCII armor. - Please check GPG/GPGME for documentation if you don't know what this means. - (Try 'man gpg' on the command line and look for 'armor') - - @param state set true if results should be ASCII armored, set false if binary + * Tell the gpg engine to use ASCII armor. Please check GPG/GPGME for + * documentation if you don't know what this means. (Try 'man gpg' on the + * command line and look for 'armor') + * + * @param state set true if results should be ASCII armored, set false if + * binary */ public void setArmor(boolean state) { gpgmeSetArmor(getInternalRepresentation(), state); } /** - Tells you, is the gpg engine is in text mode. - Please check GPG/GPGME for documentation if you don't know what this means. - - @return boolean true means text mode is on + * Tells you, is the gpg engine is in text mode. Please check GPG/GPGME for + * documentation if you don't know what this means. + * + * @return boolean true means text mode is on */ public boolean isTextmode() { return gpgmeGetTextmode(getInternalRepresentation()); } /** - Get the current text mode from the gpg engine. - Please check GPG/GPGME for documentation if you don't know what this means. - - @return boolean if textmode is currently enabled + * Get the current text mode from the gpg engine. Please check GPG/GPGME for + * documentation if you don't know what this means. + * + * @return boolean if textmode is currently enabled */ - public boolean getTextmode(){ + public boolean getTextmode() { return gpgmeGetTextmode(getInternalRepresentation()); } /** - Tell the gpg engine to set the text mode. - Please check GPG/GPGME for documentation if you don't know what this means. - - @param state set true if you want text mode switched on + * Tell the gpg engine to set the text mode. Please check GPG/GPGME for + * documentation if you don't know what this means. + * + * @param state set true if you want text mode switched on */ public void setTextmode(boolean state) { gpgmeSetTextmode(getInternalRepresentation(), state); } /** - Sets a listener, if GPGME needs to request a passphrase - from the user (or even from a program or a database..) -

- A passphrase-listener is global to a jvm. This means, - you can register only one listener. -

- I am working on this, but it is not so easy to access - jvm methods from a specific object from a non-jvm thread, - which the passphrase callback is... - - @param l a GnuPGPassphraseListener implementation - - @see com.freiheit.gnupg.GnuPGPassphraseListener + * Sets a listener, if GPGME needs to request a passphrase from the user (or + * even from a program or a database..) + *

+ * A passphrase-listener is global to a jvm. This means, you can register + * only one listener. + *

+ * I am working on this, but it is not so easy to access jvm methods from a + * specific object from a non-jvm thread, which the passphrase callback + * is... + * + * @param l a GnuPGPassphraseListener implementation + * @see com.freiheit.gnupg.GnuPGPassphraseListener */ - public void setPassphraseListener(GnuPGPassphraseListener l){ + public void setPassphraseListener(GnuPGPassphraseListener l) { _passphraseListener = l; } - public String passphraseCallback(String hint, String passphraseInfo, long wasBad){ + public String passphraseCallback(String hint, String passphraseInfo, long wasBad) { return _passphraseListener.getPassphrase(hint, passphraseInfo, wasBad); } private long[] getInternalRepresentationFromRecipients(GnuPGKey[] recipients) { - // note that these are pointers to addresses in the gnupg-for-java shared lib + // note that these are pointers to addresses in the gnupg-for-java + // shared lib long recipientsInternals[] = new long[recipients.length]; - for (int i=0; i < recipients.length; i++) { + for (int i = 0; i < recipients.length; i++) { if (recipients[i] != null) recipientsInternals[i] = recipients[i].getInternalRepresentation(); else @@ -200,22 +206,21 @@ private long[] getInternalRepresentationFromRecipients(GnuPGKey[] recipients) { return recipientsInternals; } - private boolean hasNoRecipients(GnuPGKey[] recipients){ + private boolean hasNoRecipients(GnuPGKey[] recipients) { return !(recipients != null && recipients.length > 0); } /** - Gets the public key with the supplied fingerprint from the keyring. - This is also kind of a factory method to generate key objects, - because you always need a context to access the keys in your keyring. - - @param fingerprint 16 char hex fingerprint of key in your keyring - @return GnuPGKey the public key that matches the fingerprint - - @see com.freiheit.gnupg.GnuPGKey + * Gets the public key with the supplied fingerprint from the keyring. This + * is also kind of a factory method to generate key objects, because you + * always need a context to access the keys in your keyring. + * + * @param fingerprint 16 char hex fingerprint of key in your keyring + * @return GnuPGKey the public key that matches the fingerprint + * @see com.freiheit.gnupg.GnuPGKey */ public GnuPGKey getKeyByFingerprint(String fingerprint) throws GnuPGException { - if(fingerprint == null || fingerprint.length() < 1) { + if (fingerprint == null || fingerprint.length() < 1) { return null; } else { return new GnuPGKey(this, fingerprint, false); @@ -223,18 +228,17 @@ public GnuPGKey getKeyByFingerprint(String fingerprint) throws GnuPGException { } /** - Gets the secret key with the supplied fingerprint from the keyring. - This is also kind of a factory method to generate secret key objects, - because you always need a context to access the keys in your keyring. - - @param fingerprint 16 char hex fingerprint of key in your keyring - @return GnuPGKey the secret key that matches the fingerprint - - @see com.freiheit.gnupg.GnuPGKey + * Gets the secret key with the supplied fingerprint from the keyring. This + * is also kind of a factory method to generate secret key objects, because + * you always need a context to access the keys in your keyring. + * + * @param fingerprint 16 char hex fingerprint of key in your keyring + * @return GnuPGKey the secret key that matches the fingerprint + * @see com.freiheit.gnupg.GnuPGKey */ public GnuPGKey getSecretKeyByFingerprint(String fingerprint) throws GnuPGException { - if(fingerprint == null || fingerprint.length() < 1) { + if (fingerprint == null || fingerprint.length() < 1) { return null; } else { return new GnuPGKey(this, fingerprint, true); @@ -243,126 +247,124 @@ public GnuPGKey getSecretKeyByFingerprint(String fingerprint) /** * Factory method to generate a GnuPGData-Object from a File. - * + * * @param data should not be null be readable * @return GnuPGData null is data is null or empty, otherwise a * GnuPGData-Object * @throws IOException */ public GnuPGData createDataObject(File f) throws GnuPGException, IOException { - if(f != null && f.exists() && !f.isDirectory() && f.canRead()){ + if (f != null && f.exists() && !f.isDirectory() && f.canRead()) { return new GnuPGData(f); } return null; } /** - Factory method to generate a GnuPGData-Object from a String. - - @param data should not be null and should have a length > 0 - @return GnuPGData null is data is null or empty, otherwise a GnuPGData-Object + * Factory method to generate a GnuPGData-Object from a String. + * + * @param data should not be null and should have a length > 0 + * @return GnuPGData null is data is null or empty, otherwise a + * GnuPGData-Object */ - public GnuPGData createDataObject(String data) throws GnuPGException{ - if(data == null || data.length() < 1){ + public GnuPGData createDataObject(String data) throws GnuPGException { + if (data == null || data.length() < 1) { return null; } - else{ + else { return new GnuPGData(data); } } /** - Factory method to generate a GnuPGData-Object from a byte array. - - @param data should not be null and should have a length > 0 - @return GnuPGData null is data is null or empty, otherwise a GnuPGData-Object + * Factory method to generate a GnuPGData-Object from a byte array. + * + * @param data should not be null and should have a length > 0 + * @return GnuPGData null is data is null or empty, otherwise a + * GnuPGData-Object */ - public GnuPGData createDataObject(byte[] data) throws GnuPGException{ - if(data == null || data.length < 1){ + public GnuPGData createDataObject(byte[] data) throws GnuPGException { + if (data == null || data.length < 1) { return null; } - else{ + else { return new GnuPGData(data); } } /** - Factory method to generate an empty GnuPGData-Object. - - @param data should not be null and should have a length > 0 - @return GnuPGData null is data is null or empty, otherwise a GnuPGData-Object + * Factory method to generate an empty GnuPGData-Object. + * + * @param data should not be null and should have a length > 0 + * @return GnuPGData null is data is null or empty, otherwise a + * GnuPGData-Object */ - public GnuPGData createDataObject() throws GnuPGException{ + public GnuPGData createDataObject() throws GnuPGException { return new GnuPGData(); } /** - Convenience method to generate empty key arrays. - To encrypt data, you need to supply a list of recipients - in an array. This is a little helper. It will not search for - keys! Its just an empty array. - - @param withLengthOf length of the array to generate (number of recipients) - @return GnuPGKey empty array of keys - - @see com.freiheit.gnupg.GnuPGKey + * Convenience method to generate empty key arrays. To encrypt data, you + * need to supply a list of recipients in an array. This is a little helper. + * It will not search for keys! Its just an empty array. + * + * @param withLengthOf length of the array to generate (number of + * recipients) + * @return GnuPGKey empty array of keys + * @see com.freiheit.gnupg.GnuPGKey */ - public GnuPGKey[] generateEmptyKeyArray(int withLengthOf){ - if(withLengthOf < 1){ + public GnuPGKey[] generateEmptyKeyArray(int withLengthOf) { + if (withLengthOf < 1) { return null; } - else{ + else { return new GnuPGKey[withLengthOf]; } } /** - List all public keys in keyring. - - @return GnuPGKey array of key objects with all public keys - - @see com.freiheit.gnupg.GnuPGKey - */ - public GnuPGKey[] listKeys() throws GnuPGException{ - return searchKeys(""); - } - - /** - List all secret keys in keyring. - - @return GnuPGKey array of key objects with all secret keys - - @see com.freiheit.gnupg.GnuPGKey - */ - public GnuPGKey[] listSecretKeys() throws GnuPGException{ - return searchSecretKeys(""); - } + * List all public keys in keyring. + * + * @return GnuPGKey array of key objects with all public keys + * @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey[] listKeys() throws GnuPGException { + return searchKeys(""); + } /** - Find all public keys matching query in keyring. - - @param query allows the same expressions as gpg on command line - @return GnuPGKey array of key objects with all matching keys + * List all secret keys in keyring. + * + * @return GnuPGKey array of key objects with all secret keys + * @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey[] listSecretKeys() throws GnuPGException { + return searchSecretKeys(""); + } - @see com.freiheit.gnupg.GnuPGKey + /** + * Find all public keys matching query in keyring. + * + * @param query allows the same expressions as gpg on command line + * @return GnuPGKey array of key objects with all matching keys + * @see com.freiheit.gnupg.GnuPGKey */ - public GnuPGKey[] searchKeys(String query) throws GnuPGException{ - if (query == null ) { + public GnuPGKey[] searchKeys(String query) throws GnuPGException { + if (query == null) { query = new String(""); } return gpgmeKeylist(getInternalRepresentation(), query, false); } /** - Find all keys matching query in keyring. - - @param query allows the same expressions as gpg on command line - @return GnuPGKey array of key objects with all matching keys - - @see com.freiheit.gnupg.GnuPGKey + * Find all keys matching query in keyring. + * + * @param query allows the same expressions as gpg on command line + * @return GnuPGKey array of key objects with all matching keys + * @see com.freiheit.gnupg.GnuPGKey */ - public GnuPGKey[] searchSecretKeys(String query) throws GnuPGException{ - if (query == null ) { + public GnuPGKey[] searchSecretKeys(String query) throws GnuPGException { + if (query == null) { query = new String(""); } return gpgmeKeylist(getInternalRepresentation(), query, true); @@ -370,219 +372,220 @@ public GnuPGKey[] searchSecretKeys(String query) throws GnuPGException{ /** * Encrypt plain text and return ASCII-armored text. - * + * * @param recipients array of keys to encrypt to * @param plain the plain text to be encrypted * @return String encrypted data in ASCII-armored text */ public String encryptToAscii(GnuPGKey[] recipients, String plain) { - final GnuPGData plainData = createDataObject(plain); - final String ret = encryptToAscii(recipients, plainData); - plainData.destroy(); - return ret; + final GnuPGData plainData = createDataObject(plain); + final String ret = encryptToAscii(recipients, plainData); + plainData.destroy(); + return ret; } /** * Encrypt a byte array and return ASCII-armored text. - * + * * @param recipients array of keys to encrypt to * @param plain the byte[] to be encrypted * @return String encrypted data in ASCII-armored text */ public String encryptToAscii(GnuPGKey[] recipients, byte[] plain) { - final GnuPGData plainData = createDataObject(plain); - final String ret = encryptToAscii(recipients, plainData); - plainData.destroy(); - return ret; + final GnuPGData plainData = createDataObject(plain); + final String ret = encryptToAscii(recipients, plainData); + plainData.destroy(); + return ret; } /** * Encrypt plain text and return ASCII-armored text. - * + * * @param recipients array of keys to encrypt to * @param plain the GnuPGData to be encrypted * @return String encrypted data in ASCII-armored text */ public String encryptToAscii(GnuPGKey[] recipients, GnuPGData plain) { - long l = getInternalRepresentation(); - boolean previous = gpgmeGetArmor(l); - gpgmeSetArmor(l, true); - GnuPGData cipher = createDataObject(); - encrypt(recipients, plain, cipher); - final String ret = cipher.toString(); - cipher.destroy(); - if (previous == false) // maintain the original ASCII-Armor state - gpgmeSetArmor(l, false); - return ret; + long l = getInternalRepresentation(); + boolean previous = gpgmeGetArmor(l); + gpgmeSetArmor(l, true); + GnuPGData cipher = createDataObject(); + encrypt(recipients, plain, cipher); + final String ret = cipher.toString(); + cipher.destroy(); + if (previous == false) // maintain the original ASCII-Armor state + gpgmeSetArmor(l, false); + return ret; } /** * Encrypt a byte array and return encrypted data in binary form. - * + * * @param recipients array of keys to encrypt to * @param plain the plain binary data to be encrypted * @return byte[] encrypted data in binary data */ public byte[] encryptToBinary(GnuPGKey[] recipients, byte[] plain) { - final GnuPGData plainData = createDataObject(plain); - final byte[] ret = encryptToBinary(recipients, plainData); - plainData.destroy(); - return ret; + final GnuPGData plainData = createDataObject(plain); + final byte[] ret = encryptToBinary(recipients, plainData); + plainData.destroy(); + return ret; } /** * Encrypt plain text and return encrypted data in binary form. - * + * * @param recipients array of keys to encrypt to * @param plain the plain text to be encrypted * @return byte[] encrypted data in binary data */ public byte[] encryptToBinary(GnuPGKey[] recipients, String plain) { - final GnuPGData plainData = createDataObject(plain); - final byte[] ret = encryptToBinary(recipients, plainData); - plainData.destroy(); - return ret; + final GnuPGData plainData = createDataObject(plain); + final byte[] ret = encryptToBinary(recipients, plainData); + plainData.destroy(); + return ret; } /** * Encrypt plain data and return encrypted data in binary form. - * + * * @param recipients array of keys to encrypt to * @param plain the GnuPGData to be encrypted * @return String encrypted data in ASCII-armored text */ public byte[] encryptToBinary(GnuPGKey[] recipients, GnuPGData plain) { - long l = getInternalRepresentation(); - boolean previous = gpgmeGetArmor(l); - gpgmeSetArmor(l, true); - GnuPGData cipher = createDataObject(); - encrypt(recipients, plain, cipher); - ByteArrayOutputStream baos = new ByteArrayOutputStream(plain.size()); - BufferedOutputStream out = new BufferedOutputStream(baos, 8192); - try { - cipher.write(out); - } catch (IOException e) { - e.printStackTrace(); - } - cipher.destroy(); - if (previous == false) // maintain the original ASCII-Armor state - gpgmeSetArmor(l, false); - return baos.toByteArray(); - } - - /** - Encrypts the text in plain with the public key - of each recipient. The result is returned as GnuPGData. - - @param recipients array of the keys to encrypt to - @param plain bytes to be encrypted - @return GnuPGData the encrypted data - - @see com.freiheit.gnupg.GnuPGData - @see com.freiheit.gnupg.GnuPGKey + long l = getInternalRepresentation(); + boolean previous = gpgmeGetArmor(l); + gpgmeSetArmor(l, true); + GnuPGData cipher = createDataObject(); + encrypt(recipients, plain, cipher); + ByteArrayOutputStream baos = new ByteArrayOutputStream(plain.size()); + BufferedOutputStream out = new BufferedOutputStream(baos, 8192); + try { + cipher.write(out); + } catch (IOException e) { + e.printStackTrace(); + } + cipher.destroy(); + if (previous == false) // maintain the original ASCII-Armor state + gpgmeSetArmor(l, false); + return baos.toByteArray(); + } + + /** + * Encrypts the text in plain with the public key of each + * recipient. The result is returned as GnuPGData. + * + * @param recipients array of the keys to encrypt to + * @param plain bytes to be encrypted + * @return GnuPGData the encrypted data + * @see com.freiheit.gnupg.GnuPGData + * @see com.freiheit.gnupg.GnuPGKey */ public GnuPGData encrypt(GnuPGKey[] recipients, byte[] plain) - throws GnuPGException{ + throws GnuPGException { if (hasNoRecipients(recipients) || plain == null || plain.length == 0) - throw new GnuPGException("Encryption arguments not complete."); + throw new GnuPGException("Encryption arguments not complete."); final GnuPGData plainData = createDataObject(plain); GnuPGData cipherData = createDataObject(); gpgmeOpEncrypt(this.getInternalRepresentation(), - getInternalRepresentationFromRecipients(recipients), - plainData.getInternalRepresentation(), - cipherData.getInternalRepresentation()); + getInternalRepresentationFromRecipients(recipients), + plainData.getInternalRepresentation(), + cipherData.getInternalRepresentation()); plainData.destroy(); return cipherData; } /** - Encrypts the text in plain with the public key - of each recipient. The result is returned as GnuPGData. - - @param recipients array of the keys to encrypt to - @param plain the text to be encrypted - @return GnuPGData the encrypted data - - @see com.freiheit.gnupg.GnuPGData - @see com.freiheit.gnupg.GnuPGKey + * Encrypts the text in plain with the public key of each + * recipient. The result is returned as GnuPGData. + * + * @param recipients array of the keys to encrypt to + * @param plain the text to be encrypted + * @return GnuPGData the encrypted data + * @see com.freiheit.gnupg.GnuPGData + * @see com.freiheit.gnupg.GnuPGKey */ public GnuPGData encrypt(GnuPGKey[] recipients, String plain) - throws GnuPGException{ + throws GnuPGException { if (hasNoRecipients(recipients) || plain == null || plain.equals("")) - throw new GnuPGException("Encryption arguments not complete."); + throw new GnuPGException("Encryption arguments not complete."); final GnuPGData plainData = createDataObject(plain); GnuPGData cipherData = createDataObject(); gpgmeOpEncrypt(this.getInternalRepresentation(), - getInternalRepresentationFromRecipients(recipients), - plainData.getInternalRepresentation(), - cipherData.getInternalRepresentation()); + getInternalRepresentationFromRecipients(recipients), + plainData.getInternalRepresentation(), + cipherData.getInternalRepresentation()); plainData.destroy(); return cipherData; } /** - Encrypts the data from plain with the public key - of each recipient. The result is stored in cipher. - - @param recipients Array with the public keys of all recipients - @param plain text, that should be encrypted - @param cipher text, the encrypted plain text after method call - - @see com.freiheit.gnupg.GnuPGData - @see com.freiheit.gnupg.GnuPGKey + * Encrypts the data from plain with the public key of each + * recipient. The result is stored in cipher. + * + * @param recipients Array with the public keys of all recipients + * @param plain text, that should be encrypted + * @param cipher text, the encrypted plain text after method call + * @see com.freiheit.gnupg.GnuPGData + * @see com.freiheit.gnupg.GnuPGKey */ - public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException{ - if (hasNoRecipients(recipients) || plain == null || cipher == null) - throw new GnuPGException("Encryption arguments not complete."); + public void encrypt(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) + throws GnuPGException { + if (hasNoRecipients(recipients) || plain == null || cipher == null) + throw new GnuPGException("Encryption arguments not complete."); + + // note that these are pointers to addresses in the gnupg-for-java + // shared lib + long context = this.getInternalRepresentation(); + if (gpgmeGetSignersLength(context) == 0) + gpgmeOpEncrypt(context, + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); + else + gpgmeOpEncryptSign(context, + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); + } + + public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) + throws GnuPGException { + if (hasNoRecipients(recipients) || plain == null || cipher == null) + throw new GnuPGException("Encryption-Arguments not complete."); - // note that these are pointers to addresses in the gnupg-for-java shared lib - long context = this.getInternalRepresentation(); - if (gpgmeGetSignersLength(context) == 0) - gpgmeOpEncrypt(context, - getInternalRepresentationFromRecipients(recipients), - plain.getInternalRepresentation(), - cipher.getInternalRepresentation()); - else - gpgmeOpEncryptSign(context, - getInternalRepresentationFromRecipients(recipients), - plain.getInternalRepresentation(), - cipher.getInternalRepresentation()); + gpgmeOpEncryptSign(this.getInternalRepresentation(), + getInternalRepresentationFromRecipients(recipients), + plain.getInternalRepresentation(), + cipher.getInternalRepresentation()); } - public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cipher) throws GnuPGException { - if (hasNoRecipients(recipients) || plain == null || cipher == null) - throw new GnuPGException("Encryption-Arguments not complete."); - - gpgmeOpEncryptSign(this.getInternalRepresentation(), - getInternalRepresentationFromRecipients(recipients), - plain.getInternalRepresentation(), - cipher.getInternalRepresentation()); - } - /** - Decrypts the data from cipher and stores the result - in plain. - - @param cipher text, holds the cipher to be decrypted - @param plain text, holds the decrypted text after decryption - - @see com.freiheit.gnupg.GnuPGData + * Decrypts the data from cipher and stores the result in + * plain. + * + * @param cipher text, holds the cipher to be decrypted + * @param plain text, holds the decrypted text after decryption + * @see com.freiheit.gnupg.GnuPGData */ - public void decrypt(GnuPGData cipher, GnuPGData plain) throws GnuPGException{ - if (cipher == null || plain == null) return; + public void decrypt(GnuPGData cipher, GnuPGData plain) throws GnuPGException { + if (cipher == null || plain == null) + return; gpgmeOpDecrypt(this.getInternalRepresentation(), - cipher.getInternalRepresentation(), plain.getInternalRepresentation()); + cipher.getInternalRepresentation(), plain.getInternalRepresentation()); } /** * Decrypts the data from cipher and stores the result in * plain, then verifies the signature of the data. If the - * decryption or verification fails, it throws a GnuPGException. + * decryption or verification fails, it throws a GnuPGException + * . * * @param cipher holds the data to be decrypted and verified * @param plain holds the decrypted data after decryption @@ -597,107 +600,110 @@ public void decryptVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGExcepti plain.getInternalRepresentation()); } - public void changePassphrase( GnuPGKey key ) throws GnuPGException { - if(_passphraseListener == null) throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); + public void changePassphrase(GnuPGKey key) throws GnuPGException { + if (_passphraseListener == null) + throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); - if ( key == null ) return; + if (key == null) + return; - gpgmeOpChangePassphrase( this.getInternalRepresentation(), key.getInternalRepresentation() ); + gpgmeOpChangePassphrase(this.getInternalRepresentation(), key.getInternalRepresentation()); } - /* - Not finished. - Decrypts the data in cipher and verfies the signature on the cipher. - - @param cipher encrypted and signed data - @param plain will contain the result after the method call + * Not finished. Decrypts the data in cipher and verfies the + * signature on the cipher. + * @param cipher encrypted and signed data + * @param plain will contain the result after the method call */ -// public void decryptAndVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGException{ -// if (cipher == null || plain == null) return; + // public void decryptAndVerify(GnuPGData cipher, GnuPGData plain) throws + // GnuPGException{ + // if (cipher == null || plain == null) return; -// gpgmeOpDecryptVerify(this.getInternalRepresentation(), -// cipher.getInternalRepresentation(), plain.getInternalRepresentation()); -// } + // gpgmeOpDecryptVerify(this.getInternalRepresentation(), + // cipher.getInternalRepresentation(), plain.getInternalRepresentation()); + // } /** - Signs the data in plain and stores the result in signature. - - @param plain data that you want to sign - @param signature result of the operation + * Signs the data in plain and stores the result in + * signature. + * + * @param plain data that you want to sign + * @param signature result of the operation */ - public void sign(GnuPGData plain, GnuPGData signature) throws GnuPGException{ - if (plain == null || signature == null) throw new GnuPGException("Parameters not complete or null."); + public void sign(GnuPGData plain, GnuPGData signature) throws GnuPGException { + if (plain == null || signature == null) + throw new GnuPGException("Parameters not complete or null."); gpgmeOpSign(this.getInternalRepresentation(), - plain.getInternalRepresentation(), signature.getInternalRepresentation()); + plain.getInternalRepresentation(), signature.getInternalRepresentation()); } /** - Verifies a signature. - - @param signature TODO - @param signed TODO - @param plain TODO + * Verifies a signature. + * + * @param signature TODO + * @param signed TODO + * @param plain TODO */ - public void verify(GnuPGData signature, GnuPGData signed, GnuPGData plain) throws GnuPGException{ - if (signature == null || signed == null|| plain == null) throw new GnuPGException("Parameters not complete or null."); + public void verify(GnuPGData signature, GnuPGData signed, GnuPGData plain) + throws GnuPGException { + if (signature == null || signed == null || plain == null) + throw new GnuPGException("Parameters not complete or null."); gpgmeOpVerify(this.getInternalRepresentation(), - signature.getInternalRepresentation(), - signed.getInternalRepresentation(), - plain.getInternalRepresentation()); + signature.getInternalRepresentation(), + signed.getInternalRepresentation(), + plain.getInternalRepresentation()); } /** - Adds a Signer to this context. All signature operation will uses - this/these signer(s), until you clear the signers from the context. - You remove all signers at once with a call to clearSigners(). - - @param key that should be used for signing operations - - @see com.freiheit.gnupg.GnuPGKey + * Adds a Signer to this context. All signature operation will uses + * this/these signer(s), until you clear the signers from the context. You + * remove all signers at once with a call to clearSigners(). + * + * @param key that should be used for signing operations + * @see com.freiheit.gnupg.GnuPGKey */ - public void addSigner(GnuPGKey key) throws GnuPGException{ - if(key == null) throw new GnuPGException("Parameters not complete or null."); + public void addSigner(GnuPGKey key) throws GnuPGException { + if (key == null) + throw new GnuPGException("Parameters not complete or null."); gpgmeAddSigners(getInternalRepresentation(), key.getInternalRepresentation()); } /** - Removes all signers from this context. You add Signers with addSigner(). + * Removes all signers from this context. You add Signers with addSigner(). */ - public void clearSigners() throws GnuPGException{ + public void clearSigners() throws GnuPGException { gpgmeClearSigners(getInternalRepresentation()); } - /** - Get a specific Signer at a given index. You add Signers - with addSigner(). - - @param int index to the list of Signers - @return GnuPGKey the key at index, or null if it doesn't exist - - @see com.freiheit.gnupg.GnuPGKey - */ - public GnuPGKey getSigner(int index) throws GnuPGException { - return new GnuPGKey(gpgmeGetSigner(getInternalRepresentation(), index)); - } - - /** - Gets the number of Signers currently in the GnuPGContext. You add Signers - with addSigner(). - @return long the number of Signers currently in the GnuPGContext + /** + * Get a specific Signer at a given index. You add Signers with addSigner(). + * + * @param int index to the list of Signers + * @return GnuPGKey the key at index, or null if it doesn't exist + * @see com.freiheit.gnupg.GnuPGKey + */ + public GnuPGKey getSigner(int index) throws GnuPGException { + return new GnuPGKey(gpgmeGetSigner(getInternalRepresentation(), index)); + } - @see com.freiheit.gnupg.GnuPGKey - */ - public long getSignersLength() throws GnuPGException { - return gpgmeGetSignersLength(getInternalRepresentation()); - } + /** + * Gets the number of Signers currently in the GnuPGContext. You add Signers + * with addSigner(). + * + * @return long the number of Signers currently in the GnuPGContext + * @see com.freiheit.gnupg.GnuPGKey + */ + public long getSignersLength() throws GnuPGException { + return gpgmeGetSignersLength(getInternalRepresentation()); + } /** - Imports a Key (private or public). You can supply the key in ASCII armor. + * Imports a Key (private or public). You can supply the key in ASCII armor. */ - public void importKey(GnuPGData keydata) throws GnuPGException{ + public void importKey(GnuPGData keydata) throws GnuPGException { gpgmeOpImport(getInternalRepresentation(), keydata.getInternalRepresentation()); } @@ -706,118 +712,150 @@ public void importKey(GnuPGData keydata) throws GnuPGException{ */ public void importKey(File file) throws GnuPGException, IOException { GnuPGData keydata = createDataObject(file); - if( keydata == null ) { Log.e(TAG, "importkey: parsing key data failed" ); return; } + if (keydata == null) { + Log.e(TAG, "importkey: parsing key data failed"); + return; + } gpgmeOpImport(getInternalRepresentation(), keydata.getInternalRepresentation()); } /** - This calls immediately the release method for the context - in the underlying gpgme library. This method is called by - the finalizer of the class anyway, but you can call it yourself - if you want to get rid of a context at once and don't want to - wait for the non-deterministic garbage-collector of the JVM. - */ - public void destroy(){ - if(getInternalRepresentation() != 0){ + * This calls immediately the release method for the context in the + * underlying gpgme library. This method is called by the finalizer of the + * class anyway, but you can call it yourself if you want to get rid of a + * context at once and don't want to wait for the non-deterministic + * garbage-collector of the JVM. + */ + public void destroy() { + if (getInternalRepresentation() != 0) { gpgmeRelease(getInternalRepresentation()); setInternalRepresentation(0); } } /** - Releases underlying datastructures. Simple calls the destroy() method. + * Releases underlying datastructures. Simple calls the destroy() method. */ @Override - protected void finalize(){ + protected void finalize() { destroy(); } /** - * Generates a new PGP key and stores it in the keyring. + * Generates a new PGP key and stores it in the keyring. */ public void genPgpKey(String params) throws GnuPGException { - gpgmeOpGenKey(getInternalRepresentation(),params); + gpgmeOpGenKey(getInternalRepresentation(), params); } /** - Generates a new Key. - */ - public void genKey(String params,GnuPGData pub, GnuPGData secret) throws GnuPGException{ - gpgmeOpGenKey(getInternalRepresentation(),params); + * Generates a new Key. + */ + public void genKey(String params, GnuPGData pub, GnuPGData secret) throws GnuPGException { + gpgmeOpGenKey(getInternalRepresentation(), params); } /** - Sets the engine info for the context - */ - public void setEngineInfo(int proto, String fileName, String homeDir){ + * Sets the engine info for the context + */ + public void setEngineInfo(int proto, String fileName, String homeDir) { - // note that this is a pointer to and address in the gnupg-for-java shared lib + // note that this is a pointer to and address in the gnupg-for-java + // shared + // lib long ctx = getInternalRepresentation(); - gpgmeCtxSetEngineInfo(ctx,proto,fileName,homeDir); + gpgmeCtxSetEngineInfo(ctx, proto, fileName, homeDir); } /** - * Returns the result of a key generation. This must bedirectly called, after the key - * has been generated. + * Returns the result of a key generation. This must bedirectly called, + * after the key has been generated. + * * @return the result of a key generation */ - public GnuPGGenkeyResult getGenkeyResult(){ + public GnuPGGenkeyResult getGenkeyResult() { return gpgmeOpGenkeyResult(getInternalRepresentation()); } /** * Export the keys defined by the pattern. + * * @param pattern pattern for the keys * @param reserved not used, must be set 0. For later use revered. * @param data empty data object. Will be filled with the keys. */ - public void export(String pattern, long reserved, GnuPGData data){ + public void export(String pattern, long reserved, GnuPGData data) { gpgmeOpExport(getInternalRepresentation(), pattern, 0, data.getInternalRepresentation()); } - /** - * Deletes a Key from key ring. When allowSecret, a secret Key will be deleted + * Deletes a Key from key ring. When allowSecret, a secret Key will be + * deleted + * * @param key key to delete * @param allowSecret if a secret key shall be deleted. */ - public void delete(GnuPGKey key, boolean allowSecret){ - gpgmeOpDelete(getInternalRepresentation(),key.getInternalRepresentation(),allowSecret); + public void delete(GnuPGKey key, boolean allowSecret) { + gpgmeOpDelete(getInternalRepresentation(), key.getInternalRepresentation(), allowSecret); } - /* Native methods: - All these methods are implemented as JNI calls in: - GnuPGContext.c - The naming is as close as possible to the corresponding - GPGME methods. So, if you want to know what these methods - are actually doing: Please refer to the GPGME docs. + + /* + * Native methods: All these methods are implemented as JNI calls in: + * GnuPGContext.c The naming is as close as possible to the corresponding + * GPGME methods. So, if you want to know what these methods are actually + * doing: Please refer to the GPGME docs. */ private native void gpgmeGetEngineInfo(); + private native long gpgmeNew(); + private native void gpgmeOpEncrypt(long l, long[] recipientsInternals, long m, long n); + private native void gpgmeOpDecrypt(long l, long m, long n); - private native void gpgmeOpChangePassphrase(long l, long m ); + + private native void gpgmeOpChangePassphrase(long l, long m); + private native void gpgmeRelease(long l); + private native void gpgmeOpEncryptSign(long context, long[] recipients, long plain, long cipher); + private native void gpgmeOpDecryptVerify(long context, long cipher, long plain); + private native void gpgmeOpSign(long context, long l, long m); + private native void gpgmeOpVerify(long context, long l, long m, long n); + private native GnuPGKey[] gpgmeKeylist(long l, String query, boolean secret_only); + private native void gpgmeAddSigners(long l, long m); + private native void gpgmeClearSigners(long context); + private native long gpgmeGetSigner(long context, int index); + private native long gpgmeGetSignersLength(long context); + private native void gpgmeOpImport(long context, long l); + private native void gpgmeOpExport(long context, String pattern, long reserved, long l); - private native void gpgmeOpGenKey(long context,String params); - private native void gpgmeCtxSetEngineInfo(long context,int proto,String fileName,String homeDir); + + private native void gpgmeOpGenKey(long context, String params); + + private native void gpgmeCtxSetEngineInfo(long context, int proto, String fileName, + String homeDir); + private native GnuPGGenkeyResult gpgmeOpGenkeyResult(long context); + private native void gpgmeOpDelete(long context, long l, boolean allowSecret); - //getters/setters for members, no caching, always direct access to gpgme + // getters/setters for members, no caching, always direct access to gpgme private native boolean gpgmeGetArmor(long l); + private native void gpgmeSetArmor(long l, boolean state); + private native boolean gpgmeGetTextmode(long l); + private native void gpgmeSetTextmode(long l, boolean state); } diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 237f128..57c4172 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -22,20 +22,19 @@ import java.io.OutputStream; /** - Holds the data that you want to work on and stores the results - of crypto operations. - - @author Stefan Richter, stefan@freiheit.com + * Holds the data that you want to work on and stores the results of crypto + * operations. + * + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGData extends GnuPGPeer{ +public class GnuPGData extends GnuPGPeer { /** - Use the factory methods from GnuPGContext to create GnuPGData instances. - Generates an empty data object. Use this, if you want - to create a data object to hold a result from a crypto - operation. + * Use the factory methods from GnuPGContext to create GnuPGData instances. + * Generates an empty data object. Use this, if you want to create a data + * object to hold a result from a crypto operation. */ - protected GnuPGData(){ + protected GnuPGData() { setInternalRepresentation(gpgmeDataNew()); } @@ -70,86 +69,85 @@ protected GnuPGData(File file, String mode) throws IOException, GnuPGException { } /** - Use the factory methods from GnuPGContext to create GnuPGData instances. - Generates a new data object containing the given String. - - @param str your string + * Use the factory methods from GnuPGContext to create GnuPGData instances. + * Generates a new data object containing the given String. + * + * @param str your string */ - protected GnuPGData(String str){ + protected GnuPGData(String str) { this(str.getBytes()); } /** - Use the factory methods from GnuPGContext to create GnuPGData instances. - Generates a new Data-Object containing the given byte array. - - @param data your data + * Use the factory methods from GnuPGContext to create GnuPGData instances. + * Generates a new Data-Object containing the given byte array. + * + * @param data your data */ - protected GnuPGData(byte[] data){ + protected GnuPGData(byte[] data) { long gpgmeDataNewFromMem = gpgmeDataNewFromMem(data); setInternalRepresentation(gpgmeDataNewFromMem); } - /* - FIXME: This is not working! Use it, and it will crash the JVM. - */ - public void read(InputStream in) throws IOException{ - if(in != null){ - gpgmeDataRead(getInternalRepresentation(), in); - } - } + * FIXME: This is not working! Use it, and it will crash the JVM. + */ + public void read(InputStream in) throws IOException { + if (in != null) { + gpgmeDataRead(getInternalRepresentation(), in); + } + } /** - Writes the data/string contained in this data object - to the given Java OutputStream. - - @param out OutputStream, where the data/string should be written + * Writes the data/string contained in this data object to the given Java + * OutputStream. + * + * @param out OutputStream, where the data/string should be written */ - public void write(OutputStream out) throws IOException{ + public void write(OutputStream out) throws IOException { if (out != null) { gpgmeDataWrite(getInternalRepresentation(), out); } } /** - Helper method to print out the data/string from this data object. - - @return String representation of the data contained in this data object (expect weird results with binary data) + * Helper method to print out the data/string from this data object. + * + * @return String representation of the data contained in this data object + * (expect weird results with binary data) */ @Override - public String toString(){ + public String toString() { String result = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(this.size()); - try{ + try { this.write(baos); result = baos.toString(); - } - catch(IOException ioe){ + } catch (IOException ioe) { result = ioe.getMessage(); } return result; } /** - This calls immediately the release method for the datastructure - in the underlying gpgme library. This method is called by - the finalizer of the class anyway, but you can call it yourself - if you want to get rid of this datastructure at once and don't want to - wait for the non-deterministic garbage-collector of the JVM. - */ - public void destroy(){ - if(getInternalRepresentation() != 0){ + * This calls immediately the release method for the datastructure in the + * underlying gpgme library. This method is called by the finalizer of the + * class anyway, but you can call it yourself if you want to get rid of this + * datastructure at once and don't want to wait for the non-deterministic + * garbage-collector of the JVM. + */ + public void destroy() { + if (getInternalRepresentation() != 0) { gpgmeDataRelease(getInternalRepresentation()); setInternalRepresentation(0); } } /** - Releases underlying datastructures. Simple calls the destroy() method. + * Releases underlying datastructures. Simple calls the destroy() method. */ @Override - protected void finalize(){ + protected void finalize() { destroy(); } @@ -158,10 +156,16 @@ public int size() { } private native int gpgmeSize(long l); + private native long gpgmeDataNewFromMem(byte[] plain); + private native long gpgmeDataNewFromFilename(String filename, String mode); + private native long gpgmeDataNew(); + private native void gpgmeDataWrite(long l, OutputStream out) throws IOException; + private native void gpgmeDataRelease(long l); + private native void gpgmeDataRead(long data, InputStream in) throws IOException; } diff --git a/src/com/freiheit/gnupg/GnuPGException.java b/src/com/freiheit/gnupg/GnuPGException.java index 9ef68a3..4ff7c95 100644 --- a/src/com/freiheit/gnupg/GnuPGException.java +++ b/src/com/freiheit/gnupg/GnuPGException.java @@ -15,20 +15,20 @@ package com.freiheit.gnupg; /** - If the underlying gpgme library reports an error, this exception is thrown. - Wraps all errors messages from inside gpgme. - - @author Stefan Richter, stefan@freiheit.com -*/ -public class GnuPGException extends RuntimeException{ + * If the underlying gpgme library reports an error, this exception is thrown. + * Wraps all errors messages from inside gpgme. + * + * @author Stefan Richter, stefan@freiheit.com + */ +public class GnuPGException extends RuntimeException { private static final long serialVersionUID = -775599686124698560L; /** - This Exception is normally only thrown from - within the native part of this library. - - @param msg is an error message text from gpgme + * This Exception is normally only thrown from within the native part of + * this library. + * + * @param msg is an error message text from gpgme */ GnuPGException(String msg) { super(msg); diff --git a/src/com/freiheit/gnupg/GnuPGGenkeyResult.java b/src/com/freiheit/gnupg/GnuPGGenkeyResult.java index 8deac4e..b06941d 100644 --- a/src/com/freiheit/gnupg/GnuPGGenkeyResult.java +++ b/src/com/freiheit/gnupg/GnuPGGenkeyResult.java @@ -14,6 +14,7 @@ /** * */ + package com.freiheit.gnupg; /** @@ -37,41 +38,44 @@ * @author Stefan Neumann * @version $Id$ */ -public class GnuPGGenkeyResult{ - - private String _fpr; - private boolean _primary; - private boolean _sub; - - protected GnuPGGenkeyResult(){ - } - +public class GnuPGGenkeyResult { + + private String _fpr; + private boolean _primary; + private boolean _sub; + + protected GnuPGGenkeyResult() { + } + /** - * This is the fingerprint of the key that was created. If both - * a primary and a sub key were generated, the fingerprint of - * the primary key will be returned. If the crypto engine does - * not provide the fingerprint, `it will return a null pointer. - * @return fingerprint of the created key + * This is the fingerprint of the key that was created. If both a primary + * and a sub key were generated, the fingerprint of the primary key will be + * returned. If the crypto engine does not provide the fingerprint, `it will + * return a null pointer. + * + * @return fingerprint of the created key */ - public String getFpr(){ + public String getFpr() { return _fpr; } /** - * This is a flag that is set to true if a primary key was created - * and to false if not. + * This is a flag that is set to true if a primary key was created and to + * false if not. + * * @return flag, if a primary key was created */ - public boolean isPrimary(){ - return _primary; + public boolean isPrimary() { + return _primary; } - + /** - * This is a flag that is set to true if a subkey was created and - * to false if not. + * This is a flag that is set to true if a subkey was created and to false + * if not. + * * @return flag, if a subkey was created */ - public boolean isSub(){ - return _sub; + public boolean isSub() { + return _sub; } } diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 447398c..8ba3c12 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -11,92 +11,93 @@ * * Please see COPYING for the complete licence. */ + package com.freiheit.gnupg; -import java.util.Iterator; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** - Represents a key. - You can manage and find keys using GnuPGContext. You can not - instantiate a key by yourself. You always need a context. - - @see com.freiheit.gnupg.GnuPGContext - - @author Stefan Richter, stefan@freiheit.com + * Represents a key. You can manage and find keys using GnuPGContext. You can + * not instantiate a key by yourself. You always need a context. + * + * @see com.freiheit.gnupg.GnuPGContext + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGKey extends GnuPGPeer{ +public class GnuPGKey extends GnuPGPeer { /** - This constructor is only called from within the JNI routines. - This is for example used, when a keylist search returns keys. - This is how then each key is instantiated on the java side from c. + * This constructor is only called from within the JNI routines. This is for + * example used, when a keylist search returns keys. This is how then each + * key is instantiated on the java side from c. */ protected GnuPGKey(long ptr) { // note that this is a pointer to an address in the gnupg-for-java shared lib - setInternalRepresentation(ptr); + setInternalRepresentation(ptr); } /** * Fetch a public key by its 16 hex char fingerprint String - * + * * @param context - the current GnuPGContext * @param fingerprint - the 16 hex char fingerprint String */ protected GnuPGKey(GnuPGContext context, String fingerprint) { - setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, false)); + setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, + false)); } /** * Fetch a key by its 16 hex char fingerprint String - * + * * @param context the current GnuPGContext * @param fingerprint the 16 hex char fingerprint String * @param secret_only whether to return only secret keys */ protected GnuPGKey(GnuPGContext context, String fingerprint, boolean secret_only) { - setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, secret_only)); + setInternalRepresentation(gpgmeGetKey(context.getInternalRepresentation(), fingerprint, + secret_only)); } /** - Get the Name of the default key/userid. + * Get the Name of the default key/userid. */ - public String getName(){ + public String getName() { return gpgmeGetName(getInternalRepresentation()); } /** - Get the Email-Address of the default key/userid. + * Get the Email-Address of the default key/userid. */ - public String getEmail(){ + public String getEmail() { return gpgmeGetEmail(getInternalRepresentation()); } /** - Get the Key-ID of the default key/userid. + * Get the Key-ID of the default key/userid. */ - public String getKeyID(){ + public String getKeyID() { return gpgmeGetKeyID(getInternalRepresentation()); } /** - Get the Fingerprint of the default key/userid. + * Get the Fingerprint of the default key/userid. */ - public String getFingerprint(){ + public String getFingerprint() { return gpgmeGetFingerprint(getInternalRepresentation()); } /** - Get the Comment of the default key/userid. + * Get the Comment of the default key/userid. */ - public String getComment(){ + public String getComment() { return gpgmeGetComment(getInternalRepresentation()); } /** - Get the User-ID of the default key/userid. + * Get the User-ID of the default key/userid. */ - public String getUserID(){ + public String getUserID() { return gpgmeGetUserID(getInternalRepresentation()); } @@ -145,26 +146,25 @@ public boolean hasSecretKey() { } /** - Lists all signatures of the default key/userid. - Every key can have multiple signatures. Signatures can - be incomplete. This means, that not all details (name, email-address etc.) - were downloaded from a keyserver. But you will at least see - the key-id of the signature. Use GnuPG to --refresh-keys if you - want to see all signature details. -

- Currently I am not supporting java generics for a type safe iterator, - because there are to many people still using jdk-1.4.x without generics support. - This will be changed on increasing demand. -

- @return Iterator of GnuPGSignature objects - - @see com.freiheit.gnupg.GnuPGSignature + * Lists all signatures of the default key/userid. Every key can have + * multiple signatures. Signatures can be incomplete. This means, that not + * all details (name, email-address etc.) were downloaded from a keyserver. + * But you will at least see the key-id of the signature. Use GnuPG to + * --refresh-keys if you want to see all signature details. + *

+ * Currently I am not supporting java generics for a type safe iterator, + * because there are to many people still using jdk-1.4.x without generics + * support. This will be changed on increasing demand. + *

+ * + * @return Iterator of GnuPGSignature objects + * @see com.freiheit.gnupg.GnuPGSignature */ - public Iterator getSignatures(){ + public Iterator getSignatures() { List siglist = null; GnuPGSignature sig = getSignature(); - while (sig != null){ - if (siglist == null){ + while (sig != null) { + if (siglist == null) { siglist = new ArrayList(); } siglist.add(sig); @@ -174,15 +174,15 @@ public Iterator getSignatures(){ } /** - Helper to list signatures in the toString()-method. + * Helper to list signatures in the toString()-method. */ - private String listSignatures(){ + private String listSignatures() { Iterator iter = getSignatures(); GnuPGSignature sig; StringBuffer buf = new StringBuffer(); - while(iter != null && iter.hasNext()){ - sig = (GnuPGSignature)iter.next(); + while (iter != null && iter.hasNext()) { + sig = (GnuPGSignature) iter.next(); buf.append("\t").append(sig).append("\n"); } @@ -190,16 +190,17 @@ private String listSignatures(){ } /** - Helper to get the head of the linked list - of signatures from the native space. + * Helper to get the head of the linked list of signatures from the native + * space. */ - private GnuPGSignature getSignature(){ + private GnuPGSignature getSignature() { GnuPGSignature result = null; - // note that thhis is a pointer to an address in the gnupg-for-java shared lib + // note that thhis is a pointer to an address in the gnupg-for-java shared + // lib long ptr = gpgmeGetSignature(getInternalRepresentation()); - if (ptr != 0){ + if (ptr != 0) { result = new GnuPGSignature(ptr); } @@ -207,67 +208,87 @@ private GnuPGSignature getSignature(){ } /** - Return this key with all of its signatures. - @return String multiline text with one key and 0..many signatures + * Return this key with all of its signatures. + * + * @return String multiline text with one key and 0..many signatures */ - public String toString(){ + public String toString() { StringBuffer buf = new StringBuffer(); buf.append(getKeyID()). - append(": "). - append(getName()). - append(", "). - append(getComment()). - append(", "). - append(getEmail()). - append(", "). - append("["). - append(getFingerprint()). - append("]"). - append("\n"). - append(listSignatures()); - return buf.toString(); + append(": "). + append(getName()). + append(", "). + append(getComment()). + append(", "). + append(getEmail()). + append(", "). + append("["). + append(getFingerprint()). + append("]"). + append("\n"). + append(listSignatures()); + return buf.toString(); } /** - This calls immediately the release method for the datastructure - in the underlying gpgme library. This method is called by - the finalizer of the class anyway, but you can call it yourself - if you want to get rid of this datastructure at once and don't want to - wait for the non-deterministic garbage-collector of the JVM. - */ - public void destroy(){ - if(getInternalRepresentation() != 0){ + * This calls immediately the release method for the datastructure in the + * underlying gpgme library. This method is called by the finalizer of the + * class anyway, but you can call it yourself if you want to get rid of this + * datastructure at once and don't want to wait for the non-deterministic + * garbage-collector of the JVM. + */ + public void destroy() { + if (getInternalRepresentation() != 0) { gpgmeKeyUnref(getInternalRepresentation()); setInternalRepresentation(0); } } /** - Releases underlying datastructures. Simple calls the destroy() method. + * Releases underlying datastructures. Simple calls the destroy() method. */ - protected void finalize(){ + protected void finalize() { destroy(); } private native long gpgmeGetKey(long context, String fingerprint, boolean secret); + private native long gpgmeKeyUnref(long keyptr); + private native String gpgmeGetName(long keyptr); + private native String gpgmeGetEmail(long keyptr); + private native String gpgmeGetKeyID(long keyptr); + private native String gpgmeGetFingerprint(long keyptr); + private native String gpgmeGetComment(long keyptr); + private native String gpgmeGetUserID(long keyptr); + private native long gpgmeGetSignature(long keyptr); + private native boolean gpgmeCanEncrypt(long keyptr); + private native boolean gpgmeCanSign(long keyptr); + private native boolean gpgmeCanCertify(long keyptr); + private native boolean gpgmeCanAuthenticate(long keyptr); + private native boolean gpgmeIsRevoked(long keyptr); + private native boolean gpgmeIsExpired(long keyptr); + private native boolean gpgmeIsDisabled(long keyptr); + private native boolean gpgmeIsInvalid(long keyptr); + private native boolean gpgmeIsQualified(long keyptr); + private native boolean gpgmeIsSecret(long keyptr); + private native boolean gpgmeHasSecretKey(long keyptr); } diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java index 52ef56c..0904a18 100644 --- a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java +++ b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java @@ -11,44 +11,43 @@ * * Please see COPYING for the complete licence. */ + package com.freiheit.gnupg; import java.io.BufferedReader; -import java.io.InputStreamReader; import java.io.IOException; +import java.io.InputStreamReader; /** - Requests a passphrase for a crypto operation from the command line. - This is triggered by gpgme. You must register this as a listener - to the GnuPGContext. It stills echoes the passphrase on the console. - Remember, this is an alpha release... - - @see com.freiheit.gnupg.GnuPGContext - - @author Stefan Richter, stefan@freiheit.com + * Requests a passphrase for a crypto operation from the command line. This is + * triggered by gpgme. You must register this as a listener to the GnuPGContext. + * It stills echoes the passphrase on the console. Remember, this is an alpha + * release... + * + * @see com.freiheit.gnupg.GnuPGContext + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGPassphraseConsole implements GnuPGPassphraseListener{ +public class GnuPGPassphraseConsole implements GnuPGPassphraseListener { private BufferedReader _reader; /** - Default-Constructor. + * Default-Constructor. */ - public GnuPGPassphraseConsole(){ + public GnuPGPassphraseConsole() { _reader = new BufferedReader(new InputStreamReader(System.in)); } /** - Prints to the console, asks for the passphrase and returns it to gpgme. + * Prints to the console, asks for the passphrase and returns it to gpgme. */ - public String getPassphrase(String hint, String passphraseInfo, long wasBad){ + public String getPassphrase(String hint, String passphraseInfo, long wasBad) { StringBuffer prompt = new StringBuffer("Enter GnuPG Passphrase ("); prompt.append(hint).append("): "); System.out.print(prompt.toString()); String line = null; - try{ + try { line = _reader.readLine(); - } - catch(IOException e){ + } catch (IOException e) { e.printStackTrace(); return null; } diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java index 994315f..2aa896b 100644 --- a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java +++ b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java @@ -11,35 +11,31 @@ * * Please see COPYING for the complete licence. */ + package com.freiheit.gnupg; /** - This is the listener interface you need to implement, if you want - to react to the passphrase callbacks of the gpgme library for - yourself. In this way, you can for example lookup passphrases from a - database or so and return them to gpgme. - - There are also two pre-fabricated listener. - @see com.freiheit.gnupg.GnuPGPassphraseWindow - @see com.freiheit.gnupg.GnuPGPassphraseConsole - - @author Stefan Richter, stefan@freiheit.com + * This is the listener interface you need to implement, if you want to react to + * the passphrase callbacks of the gpgme library for yourself. In this way, you + * can for example lookup passphrases from a database or so and return them to + * gpgme. There are also two pre-fabricated listener. + * + * @see com.freiheit.gnupg.GnuPGPassphraseWindow + * @see com.freiheit.gnupg.GnuPGPassphraseConsole + * @author Stefan Richter, stefan@freiheit.com */ -public interface GnuPGPassphraseListener{ +public interface GnuPGPassphraseListener { /** - This method will be called by gpgme, if a passphrase is necessary - to complete a crypto operation. - - Implement this interface and register it with the GnuPGContext - on which you are operating. - - @param hint TODO - @param passphraseInfo TODO - @param wasBad TODO - - @return passphrase to be supplied to gpgme callback (MUST include a \n at the end of the string) - - @see com.freiheit.gnupg.GnuPGContext + * This method will be called by gpgme, if a passphrase is necessary to + * complete a crypto operation. Implement this interface and register it + * with the GnuPGContext on which you are operating. + * + * @param hint TODO + * @param passphraseInfo TODO + * @param wasBad TODO + * @return passphrase to be supplied to gpgme callback (MUST include a \n at + * the end of the string) + * @see com.freiheit.gnupg.GnuPGContext */ public String getPassphrase(String hint, String passphraseInfo, long wasBad); } diff --git a/src/com/freiheit/gnupg/GnuPGPeer.java b/src/com/freiheit/gnupg/GnuPGPeer.java index 2e2331a..5dcf9cf 100644 --- a/src/com/freiheit/gnupg/GnuPGPeer.java +++ b/src/com/freiheit/gnupg/GnuPGPeer.java @@ -11,32 +11,33 @@ * * Please see COPYING for the complete licence. */ + package com.freiheit.gnupg; /** - Peer Class to hold the pointers to connect to the underlying gpgme library. - This is the base class for all GnuPG*.java Classes. DO NOT USE IT. - It is not intended for library users. - - @author Stefan Richter, stefan@freiheit.com + * Peer Class to hold the pointers to connect to the underlying gpgme library. + * This is the base class for all GnuPG*.java Classes. DO NOT USE IT. It is not + * intended for library users. + * + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGPeer{ +public class GnuPGPeer { // note that this is a pointer to an address in the gnupg-for-java shared lib protected long _internalRepresentation; /** - DO NOT USE IT. This is only use from inside the library. + * DO NOT USE IT. This is only use from inside the library. */ - protected void setInternalRepresentation(long ptr){ - // note that this is a pointer to an address in the gnupg-for-java shared lib + protected void setInternalRepresentation(long ptr) { + // note that this is a pointer to an address in the gnupg-for-java shared lib _internalRepresentation = ptr; } /** - DO NOT USE IT. This is only use from inside the library. + * DO NOT USE IT. This is only use from inside the library. */ - protected long getInternalRepresentation(){ - // note that this is a pointer to an address in the gnupg-for-java shared lib + protected long getInternalRepresentation() { + // note that this is a pointer to an address in the gnupg-for-java shared lib return _internalRepresentation; } } diff --git a/src/com/freiheit/gnupg/GnuPGSignature.java b/src/com/freiheit/gnupg/GnuPGSignature.java index d989d06..3dc5627 100644 --- a/src/com/freiheit/gnupg/GnuPGSignature.java +++ b/src/com/freiheit/gnupg/GnuPGSignature.java @@ -15,132 +15,129 @@ package com.freiheit.gnupg; /** - Represents a signature from a key. - - A signature doesn't stand alone. It is always bound to a key. - So if you want to see a signature, you first have to get a key - via the GnuPGContext. -

- This class accesses directly the corresponding structure "under the hood" - and stores no data in java members. This means, that every call of - a method also results in a native call to access gpgme memory. - - @author Stefan Richter, stefan@freiheit.com - - @see com.freiheit.gnupg.GnuPGContext + * Represents a signature from a key. A signature doesn't stand alone. It is + * always bound to a key. So if you want to see a signature, you first have to + * get a key via the GnuPGContext. + *

+ * This class accesses directly the corresponding structure "under the hood" and + * stores no data in java members. This means, that every call of a method also + * results in a native call to access gpgme memory. + * + * @author Stefan Richter, stefan@freiheit.com + * @see com.freiheit.gnupg.GnuPGContext */ -public class GnuPGSignature extends GnuPGPeer{ +public class GnuPGSignature extends GnuPGPeer { /** - This constructor is only called from GnuPGKey. It is called - when the lib browses thru the linked list of signatures of each key. - - @see com.freiheit.gnupg.GnuPGKey + * This constructor is only called from GnuPGKey. It is called when the lib + * browses thru the linked list of signatures of each key. + * + * @see com.freiheit.gnupg.GnuPGKey */ - protected GnuPGSignature(long ptr){ - // note that this is a pointer to an address in the gnupg-for-java shared lib - setInternalRepresentation(ptr); + protected GnuPGSignature(long ptr) { + // note that this is a pointer to an address in the gnupg-for-java shared lib + setInternalRepresentation(ptr); } /** - Is signature key revoked? - - @return true, if revoked + * Is signature key revoked? + * + * @return true, if revoked */ - public boolean isRevoked(){ + public boolean isRevoked() { return gpgmeGetRevoked(getInternalRepresentation()); } /** - Is signature key expired? - - @return true, if expired + * Is signature key expired? + * + * @return true, if expired */ - public boolean isExpired(){ + public boolean isExpired() { return gpgmeGetExpired(getInternalRepresentation()); } /** - Is signature key invalid? - - @return true, if invalid + * Is signature key invalid? + * + * @return true, if invalid */ - public boolean isInvalid(){ + public boolean isInvalid() { return gpgmeGetInvalid(getInternalRepresentation()); } /** - Is signature key exportable? - - @return true, if exportable + * Is signature key exportable? + * + * @return true, if exportable */ - public boolean isExportable(){ + public boolean isExportable() { return gpgmeGetExportable(getInternalRepresentation()); } /** - Returns Key-ID of signature key. - - @return Key-ID + * Returns Key-ID of signature key. + * + * @return Key-ID */ - public String getKeyID(){ + public String getKeyID() { return gpgmeGetKeyID(getInternalRepresentation()); } /** - Returns User-ID of signer. - - @return User-ID + * Returns User-ID of signer. + * + * @return User-ID */ - public String getUserID(){ + public String getUserID() { return gpgmeGetUserID(getInternalRepresentation()); } /** - Returns Name of signer. - - @return Name + * Returns Name of signer. + * + * @return Name */ - public String getName(){ + public String getName() { return gpgmeGetName(getInternalRepresentation()); } /** - Returns Email-Address of signer. - - @return Email-Address + * Returns Email-Address of signer. + * + * @return Email-Address */ - public String getEmail(){ + public String getEmail() { return gpgmeGetEmail(getInternalRepresentation()); } /** - Returns Comment. - - @return Comment + * Returns Comment. + * + * @return Comment */ - public String getComment(){ + public String getComment() { return gpgmeGetComment(getInternalRepresentation()); } /** - Checks, if all signature details are available. - - @return true, if more info than the keyid is available + * Checks, if all signature details are available. + * + * @return true, if more info than the keyid is available */ - public boolean hasDetails(){ + public boolean hasDetails() { return !getName().equals(""); } /** - String-Representation of this Signature. - - @return String single line of text with name, comment etc. + * String-Representation of this Signature. + * + * @return String single line of text with name, comment etc. */ - public String toString(){ + public String toString() { StringBuffer buf = new StringBuffer(); buf.append(getKeyID()); - if(hasDetails()){ + if (hasDetails()) { buf.append(", "); buf.append(getName()); buf.append(", "); @@ -148,40 +145,47 @@ public String toString(){ buf.append(", "); buf.append(getEmail()); } - else{ + else { buf.append(" "); } return buf.toString(); } /** - Gets the next pointer in the gpgme_key_sig_t structure. - - @return new GnuPGSignature-Object + * Gets the next pointer in the gpgme_key_sig_t structure. + * + * @return new GnuPGSignature-Object */ - protected GnuPGSignature getNextSignature(){ + protected GnuPGSignature getNextSignature() { GnuPGSignature result = null; - // note that this is a pointer to an address in the gnupg-for-java shared lib + // note that this is a pointer to an address in the gnupg-for-java shared lib long next = gpgmeGetNextSignature(getInternalRepresentation()); - if(next != 0){ + if (next != 0) { result = new GnuPGSignature(next); } return result; } - //native method declarations: - private native boolean gpgmeGetRevoked(long l); + // native method declarations: + private native boolean gpgmeGetRevoked(long l); + private native boolean gpgmeGetExpired(long l); + private native boolean gpgmeGetInvalid(long l); + private native boolean gpgmeGetExportable(long l); private native String gpgmeGetKeyID(long l); + private native String gpgmeGetUserID(long l); + private native String gpgmeGetName(long l); + private native String gpgmeGetEmail(long l); + private native String gpgmeGetComment(long l); private native long gpgmeGetNextSignature(long l); From 57a073ae86ce2ad3681571143f58a8bf29f8dc74 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Jun 2013 15:24:35 -0400 Subject: [PATCH 43/90] add simple, java-ish decrypt methods --- src/com/freiheit/gnupg/GnuPGContext.java | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index f9732b1..bc959f6 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -565,6 +565,48 @@ public void encryptAndSign(GnuPGKey[] recipients, GnuPGData plain, GnuPGData cip cipher.getInternalRepresentation()); } + /** + * Decrypts the data from cipher and returns the result. + * + * @param cipher the data to be decrypted + * @return plain the resulting decrypted data + * @see com.freiheit.gnupg.GnuPGData + */ + public GnuPGData decrypt(byte[] cipher) throws GnuPGException { + if (cipher == null || cipher.length == 0) + throw new GnuPGException("Encryption arguments not complete."); + + GnuPGData plainData = createDataObject(); + final GnuPGData cipherData = createDataObject(cipher); + + gpgmeOpDecrypt(this.getInternalRepresentation(), + cipherData.getInternalRepresentation(), + plainData.getInternalRepresentation()); + cipherData.destroy(); + return plainData; + } + + /** + * Decrypts the data from cipher and returns the result. + * + * @param cipher the data to be decrypted + * @return plain the resulting decrypted data + * @see com.freiheit.gnupg.GnuPGData + */ + public GnuPGData decrypt(String cipher) throws GnuPGException { + if (cipher == null || cipher.length() == 0) + throw new GnuPGException("Encryption arguments not complete."); + + GnuPGData plainData = createDataObject(); + final GnuPGData cipherData = createDataObject(cipher); + + gpgmeOpDecrypt(this.getInternalRepresentation(), + cipherData.getInternalRepresentation(), + plainData.getInternalRepresentation()); + cipherData.destroy(); + return plainData; + } + /** * Decrypts the data from cipher and stores the result in * plain. From eed6e155849e6a703e376e611608b6a11ae36b5a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 13 Aug 2013 12:44:03 -0400 Subject: [PATCH 44/90] fix crash when get sigs on a key when none are returned If a key has no signature data, or the key list most does not include signature data (i.e. GPGME_KEYLIST_MODE_SIGS), then siglist will be null. The methods that call getSignatures() should handle a null return value. closes #1698 --- src/com/freiheit/gnupg/GnuPGKey.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 8ba3c12..860410c 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -170,7 +170,10 @@ public Iterator getSignatures() { siglist.add(sig); sig = sig.getNextSignature(); } - return siglist.listIterator(); + if (siglist == null) + return null; + else + return siglist.listIterator(); } /** From 5a11f75f5a0c9c0d7e9c597dbc817889983612f3 Mon Sep 17 00:00:00 2001 From: Abel Luck Date: Tue, 3 Dec 2013 18:44:36 +0100 Subject: [PATCH 45/90] format JNI C code with astyle. styled included in documentation refs #1629 --- .gitignore | 1 + README.md | 4 + format-code.sh | 18 + jni/GnuPGContext.c | 768 ++++++++++++++++++++-------------------- jni/GnuPGData.c | 116 +++--- jni/GnuPGGenkeyResult.c | 18 +- jni/GnuPGKey.c | 90 ++--- jni/GnuPGSignature.c | 44 +-- jni/gpgmeutils.c | 68 ++-- jni/gpgmeutils.h | 22 +- 10 files changed, 586 insertions(+), 563 deletions(-) create mode 100755 format-code.sh diff --git a/.gitignore b/.gitignore index 90b27ce..a37b0a5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ build/ dist/ hs_err_pid*.log jni/*.o +jni/*.orig lib/libgnupg-for-java.so diff --git a/README.md b/README.md index bf6fadb..43f89ec 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,7 @@ this to the jar and extend the loading mechanism to load a DLL on a Windows plat instead of loading a .so lib. +## Hacking Notes + +Please conform to our code format standard. For C files use format-code.sh. + diff --git a/format-code.sh b/format-code.sh new file mode 100755 index 0000000..f6a53dd --- /dev/null +++ b/format-code.sh @@ -0,0 +1,18 @@ +#/bin/bash + +ASTYLE=`which astyle 2> /dev/null` +if [[ $? -ne 0 ]]; then + echo "astyle code formatter not installed. aborting." + exit 1 +fi + +$ASTYLE --help 2>&1 | grep "pad-first-paren-out" > /dev/null +if [[ $? -eq 0 ]]; then + ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --unpad-paren --pad-first-paren-out --pad-header --align-pointer=type --align-reference=type" +else + ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --pad-header --align-pointer=type --align-reference=type" +fi + +$ASTYLE $ASTYLE_ARGS jni/*.h +$ASTYLE $ASTYLE_ARGS jni/*.c + diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 9de2336..f40f83c 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -16,19 +16,19 @@ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "GnuPGContext", __VA_ARGS__) -JavaVM *_jvm; +JavaVM* _jvm; void* passphrase_cb = NULL; /* gpgme_error_t passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, - int prev_was_bad, int fd) + int prev_was_bad, int fd) { jobject self = (jobject) hook; if (self == NULL) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } JNIEnv *env; @@ -37,49 +37,49 @@ passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, jclass cls = (*env)->GetObjectClass(env, self); if (cls == NULL) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } char methodDescr[] = - "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"; + "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"; jmethodID mid = - (*env)->GetMethodID(env, cls, "passphraseCallback", methodDescr); + (*env)->GetMethodID(env, cls, "passphraseCallback", methodDescr); if (mid == NULL) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } //jbyte *hint = (*env)->NewStringUTF(env, uid_hint); jstring hint = (*env)->NewStringUTF(env, uid_hint); if (hint == NULL) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } jstring pphrinfo = (*env)->NewStringUTF(env, passphrase_info); if (pphrinfo == NULL) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } //jbyte *pphr;//passphrase is return value from callback to Java - jstring pphr; //passphrase is return value from callback to Java + jstring pphr; //passphrase is return value from callback to Java pphr = (*env)->CallObjectMethod(env, self, mid, hint, pphrinfo, (jlong)0); if (pphr == NULL) { - return GPG_ERR_CANCELED; + return GPG_ERR_CANCELED; } int len = (*env)->GetStringLength(env, pphr); - char buf[len + 1]; //leave the last char for newline + char buf[len + 1]; //leave the last char for newline //TODO: Check for errors after the next call?! (*env)->GetStringUTFRegion(env, pphr, 0, len, buf); - buf[len] = '\n'; //add the newline to the end... + buf[len] = '\n'; //add the newline to the end... ssize_t written; written = write(fd, buf, len); if (written == -1) { - return GPG_ERR_GENERAL; + return GPG_ERR_GENERAL; } return GPG_ERR_NO_ERROR; @@ -87,15 +87,15 @@ passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, */ JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved) +JNI_OnLoad(JavaVM* vm, void* reserved) { _jvm = vm; #ifdef __ANDROID__ // TODO get the actual gpgAppOpt path from Java // we need to set LD_LIBRARY_PATH because gpgme calls the cmd line utils - const char *ldLibraryPath = getenv("LD_LIBRARY_PATH"); - const char *gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; + const char* ldLibraryPath = getenv("LD_LIBRARY_PATH"); + const char* gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; size_t newPathLen = strlen(ldLibraryPath) + strlen(gpgAppOpt) + 2; char newPath[newPathLen]; snprintf(newPath, newPathLen, "%s:%s", gpgAppOpt, ldLibraryPath); @@ -113,7 +113,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo(JNIEnv * env, jobject self) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo(JNIEnv* env, jobject self) { gpgme_engine_info_t engineInfo; gpgme_get_engine_info(&engineInfo); @@ -123,12 +123,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetEngineInfo(JNIEnv * env, jobject se UTILS_setStringMember(env, self, cls, "_version", engineInfo->version); UTILS_setStringMember(env, self, cls, "_filename", engineInfo->file_name); UTILS_setStringMember(env, self, cls, "_reqversion", - engineInfo->req_version); + engineInfo->req_version); UTILS_setIntMember(env, self, cls, "_protocol", engineInfo->protocol); } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv* env, jobject self) { gpgme_ctx_t ctx; gpgme_new(&ctx); @@ -140,12 +140,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeNew(JNIEnv * env, jobject self) } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, - jobject self, - jlong context, - jlongArray recipients, - jlong plain, - jlong cipher) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv* env, + jobject self, + jlong context, + jlongArray recipients, + jlong plain, + jlong cipher) { gpgme_error_t err; @@ -153,7 +153,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, jsize len = (*env)->GetArrayLength(env, recipients); //allocate a new array with one field larger then number of recipient keys - gpgme_key_t keys[len + 1]; //allowed in C99 Standard...and useful!!! + gpgme_key_t keys[len + 1]; //allowed in C99 Standard...and useful!!! // disabled on werners behalf (33% of the work) // overriden bei sebastian.mangels@freiheit.com, @@ -161,69 +161,69 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv * env, //gpgme_set_armor( CONTEXT(context), 0 ); if (UTILS_copyRecipientsFromJvm(env, recipients, keys) < 1) { - return; + return; } - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } //call gpgme library function for encryption err = gpgme_op_encrypt(CONTEXT(context), keys, GPGME_ENCRYPT_ALWAYS_TRUST, - DATA(plain), DATA(cipher)); + DATA(plain), DATA(cipher)); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } -/* err = gpgme_op_encrypt_start(CONTEXT(context), keys, GPGME_ENCRYPT_ALWAYS_TRUST, (gpgme_data_t)plain, (gpgme_data_t)cipher); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + /* err = gpgme_op_encrypt_start(CONTEXT(context), keys, GPGME_ENCRYPT_ALWAYS_TRUST, (gpgme_data_t)plain, (gpgme_data_t)cipher); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv * env, - jobject self, - jlong context, - jlong cipher, - jlong plain) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv* env, + jobject self, + jlong context, + jlong cipher, + jlong plain) { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void *)self); + gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void*)self); - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_decrypt(CONTEXT(context), DATA(cipher), DATA(plain)); if (UTILS_onErrorThrowException(env, err)) { - return; - } -/* err = gpgme_op_decrypt_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + return; + } + /* err = gpgme_op_decrypt_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } static void flush_data(gpgme_data_t dh) @@ -234,15 +234,15 @@ static void flush_data(gpgme_data_t dh) ret = gpgme_data_seek(dh, 0, SEEK_SET); while ((ret = gpgme_data_read(dh, buf, 100)) > 0) - fwrite(buf, ret, 1, stdout); + fwrite(buf, ret, 1, stdout); } gpgme_error_t -edit_fnc(void *opaque, gpgme_status_code_t status, const char *args, int fd) +edit_fnc(void* opaque, gpgme_status_code_t status, const char* args, int fd) { - char *result = NULL; + char* result = NULL; gpgme_data_t out = (gpgme_data_t)opaque; fputs("[-- Response --]\n", stdout); @@ -251,30 +251,30 @@ edit_fnc(void *opaque, gpgme_status_code_t status, const char *args, int fd) fprintf(stdout, "[-- Code: %i, %s --]\n", status, args); if (fd >= 0) { - if (!strcmp(args, "keyedit.prompt")) { - static int switcher = 0; - - if (!switcher) { - result = "passwd"; - switcher++; - } else { - result = "save"; - switcher--; - } - - } else if (!strcmp(args, "keyedit.save.okay")) { - result = "Y"; - } else if (!strcmp(args, "keygen.valid")) { - result = "0"; - } else if (!strcmp(args, "change_passwd.empty.okay")) { - result = "N"; - } + if (!strcmp(args, "keyedit.prompt")) { + static int switcher = 0; + + if (!switcher) { + result = "passwd"; + switcher++; + } else { + result = "save"; + switcher--; + } + + } else if (!strcmp(args, "keyedit.save.okay")) { + result = "Y"; + } else if (!strcmp(args, "keygen.valid")) { + result = "0"; + } else if (!strcmp(args, "change_passwd.empty.okay")) { + result = "N"; + } } if (result) { - fprintf(stdout, "[-- Command: %s --]\n", result); - write(fd, result, strlen(result)); - write(fd, "\n", 1); + fprintf(stdout, "[-- Command: %s --]\n", result); + write(fd, result, strlen(result)); + write(fd, "\n", 1); } return 0; } @@ -282,10 +282,10 @@ edit_fnc(void *opaque, gpgme_status_code_t status, const char *args, int fd) JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv * env, - jobject self, - jlong context, - jlong keydata) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv* env, + jobject self, + jlong context, + jlong keydata) { gpgme_error_t err; @@ -295,12 +295,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv * env, err = gpgme_data_new(&out); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_edit(CONTEXT(context), KEY(keydata), edit_fnc, out, out); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } fputs("[-- Last response --]\n", stdout); @@ -308,31 +308,31 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv * env, gpgme_data_release(out); -/* err = gpgme_op_decrypt_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + /* err = gpgme_op_decrypt_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeRelease(JNIEnv * env, - jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeRelease(JNIEnv* env, + jobject self, + jlong context) { gpgme_release(CONTEXT(context)); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv * env, - jobject self, - jlong context, - jlongArray recipients, - jlong plain, - jlong cipher) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv* env, + jobject self, + jlong context, + jlongArray recipients, + jlong plain, + jlong cipher) { gpgme_error_t err; @@ -341,156 +341,156 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv * env, jsize len = (*env)->GetArrayLength(env, recipients); gpgme_key_t keys[len + 1]; if (UTILS_copyRecipientsFromJvm(env, recipients, keys) < 1) { - return; + return; } - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_encrypt_sign(CONTEXT(context), keys, - GPGME_ENCRYPT_ALWAYS_TRUST, DATA(plain), - DATA(cipher)); + GPGME_ENCRYPT_ALWAYS_TRUST, DATA(plain), + DATA(cipher)); if (UTILS_onErrorThrowException(env, err)) { - return; - } -/* err = gpgme_op_encrypt_sign_start(CONTEXT(context), keys, GPGME_ENCRYPT_ALWAYS_TRUST, (gpgme_data_t)plain, (gpgme_data_t)cipher); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + return; + } + /* err = gpgme_op_encrypt_sign_start(CONTEXT(context), keys, GPGME_ENCRYPT_ALWAYS_TRUST, (gpgme_data_t)plain, (gpgme_data_t)cipher); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv * env, - jobject self, - jlong context, - jlong cipher, - jlong plain) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv* env, + jobject self, + jlong context, + jlong cipher, + jlong plain) { gpgme_error_t err; gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_decrypt_verify(CONTEXT(context), DATA(cipher), DATA(plain)); if (UTILS_onErrorThrowException(env, err)) { - return; - } -/* err = gpgme_op_decrypt_verify_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + return; + } + /* err = gpgme_op_decrypt_verify_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv * env, - jobject self, - jlong context, - jlong plain, - jlong signature) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv* env, + jobject self, + jlong context, + jlong plain, + jlong signature) { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void *) self); + gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void*) self); - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(signature)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(signature)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_sign(CONTEXT(context), DATA(plain), DATA(signature), - GPGME_SIG_MODE_CLEAR); + GPGME_SIG_MODE_CLEAR); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } -/* err = gpgme_op_sign_start(CONTEXT(context), (gpgme_data_t)plain, (gpgme_data_t)signature, GPGME_SIG_MODE_NORMAL); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + /* err = gpgme_op_sign_start(CONTEXT(context), (gpgme_data_t)plain, (gpgme_data_t)signature, GPGME_SIG_MODE_NORMAL); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 0); */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 0); */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv * env, - jobject self, - jlong context, - jlong signature, - jlong signedtxt, - jlong plain) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv* env, + jobject self, + jlong context, + jlong signature, + jlong signedtxt, + jlong plain) { gpgme_error_t err; gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - err = gpgme_data_rewind(DATA(signature)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(signature)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(signedtxt)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(signedtxt)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_verify(CONTEXT(context), DATA(signature), DATA(signedtxt), - DATA(plain)); + DATA(plain)); if (UTILS_onErrorThrowException(env, err)) { - return; - } -/* err = gpgme_op_verify_start(CONTEXT(context), (gpgme_data_t)signature, (gpgme_data_t)signedtxt, (gpgme_data_t)plain); */ -/* if(UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ -/* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 0); */ -/* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ -/* return; */ -/* } */ + return; + } + /* err = gpgme_op_verify_start(CONTEXT(context), (gpgme_data_t)signature, (gpgme_data_t)signedtxt, (gpgme_data_t)plain); */ + /* if(UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ + /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 0); */ + /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ + /* return; */ + /* } */ } JNIEXPORT jobjectArray JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, - jobject self, - jlong context, - jstring query, - jboolean secret_only) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, + jobject self, + jlong context, + jstring query, + jboolean secret_only) { gpgme_error_t err; gpgme_key_t key; @@ -501,257 +501,257 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv * env, //copy string object from java to native string const jsize query_len = (*env)->GetStringLength(env, query); LOGD("query length %d\n", query_len); - const jbyte *query_str = (jbyte *)(*env)->GetStringUTFChars(env, query, - NULL); + const jbyte* query_str = (jbyte*)(*env)->GetStringUTFChars(env, query, + NULL); //get the right constructor to invoke for every key in result set jclass keyClass; keyClass = (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGKey"); if (keyClass == NULL) { - return NULL; + return NULL; } jmethodID cid; //get the constructor, that accepts a long as param (that is a ptr to a key).. cid = (*env)->GetMethodID(env, keyClass, "", "(J)V"); if (cid == NULL) { - return NULL; + return NULL; } //loop two times: one for counting, second for generating result array - int is_counting = 0; //loop 1: counting number of keys in result - int is_working = 1; //loop 2: generating result array - - int i = 0; //loop counter - int j = 0; //index in result array, used only in second loop run... - for (i = 0; i < 2; i++) { //loops [0..1] - err = gpgme_op_keylist_start(CONTEXT(context), - query_len > 0 ? (const char *)query_str : NULL, - secret_only); - if (UTILS_onErrorThrowException(env, err)) { - (*env)->ReleaseStringUTFChars(env, query, (const char *)query_str); - return NULL; - } - - while (!err) { - err = gpgme_op_keylist_next(CONTEXT(context), &key); - if ((gpg_err_code(err) != GPG_ERR_EOF) - && UTILS_onErrorThrowException(env, err)) { - return NULL; - } - - if (is_counting == i && key != NULL) { //only true in first loop: i=0 - num_keys_found++; //increment result count - gpgme_key_release(key); - } else if (is_working == i && key != NULL) { //only true in second loop: i=1 - if (result == NULL) { - result = (*env)->NewObjectArray(env, - num_keys_found, - keyClass, - NULL); - } - keyObj = (*env)->NewObject(env, keyClass, cid, LNG(key)); - (*env)->SetObjectArrayElement(env, result, j++, keyObj); - } else { - //FIXME: Can not happen...but should be checked -> throwing exception? - } - key = NULL; - - } //end while - - } //end for + int is_counting = 0; //loop 1: counting number of keys in result + int is_working = 1; //loop 2: generating result array + + int i = 0; //loop counter + int j = 0; //index in result array, used only in second loop run... + for (i = 0; i < 2; i++) { //loops [0..1] + err = gpgme_op_keylist_start(CONTEXT(context), + query_len > 0 ? (const char*)query_str : NULL, + secret_only); + if (UTILS_onErrorThrowException(env, err)) { + (*env)->ReleaseStringUTFChars(env, query, (const char*)query_str); + return NULL; + } + + while (!err) { + err = gpgme_op_keylist_next(CONTEXT(context), &key); + if ((gpg_err_code(err) != GPG_ERR_EOF) + && UTILS_onErrorThrowException(env, err)) { + return NULL; + } + + if (is_counting == i && key != NULL) { //only true in first loop: i=0 + num_keys_found++; //increment result count + gpgme_key_release(key); + } else if (is_working == i && key != NULL) { //only true in second loop: i=1 + if (result == NULL) { + result = (*env)->NewObjectArray(env, + num_keys_found, + keyClass, + NULL); + } + keyObj = (*env)->NewObject(env, keyClass, cid, LNG(key)); + (*env)->SetObjectArrayElement(env, result, j++, keyObj); + } else { + //FIXME: Can not happen...but should be checked -> throwing exception? + } + key = NULL; + + } //end while + + } //end for //..and release the query string for gc.. - (*env)->ReleaseStringUTFChars(env, query, (const char *) query_str); + (*env)->ReleaseStringUTFChars(env, query, (const char*) query_str); return result; } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners(JNIEnv * env, - jobject self, - jlong context, - jlong key) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeAddSigners(JNIEnv* env, + jobject self, + jlong context, + jlong key) { gpgme_error_t err; err = gpgme_signers_add(CONTEXT(context), KEY(key)); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeClearSigners(JNIEnv * env, - jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeClearSigners(JNIEnv* env, + jobject self, + jlong context) { gpgme_signers_clear(CONTEXT(context)); } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSigner(JNIEnv * env, - jobject self, - jlong context, - jint index) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSigner(JNIEnv* env, + jobject self, + jlong context, + jint index) { gpgme_key_t key = gpgme_signers_enum(CONTEXT(context), index); return LNG(key); } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSignersLength(JNIEnv * env, - jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSignersLength(JNIEnv* env, + jobject self, + jlong context) { return (CONTEXT(context)->signers_len); } -void check_result(gpgme_import_result_t result, char *fpr, int secret) +void check_result(gpgme_import_result_t result, char* fpr, int secret) { //TODO: Throw exception for possible errors... if (result->considered != 1) { - fprintf(stderr, "Unexpected number of considered keys %i\n", - result->considered); + fprintf(stderr, "Unexpected number of considered keys %i\n", + result->considered); } if (result->no_user_id != 0) { - fprintf(stderr, "Unexpected number of user ids %i\n", - result->no_user_id); + fprintf(stderr, "Unexpected number of user ids %i\n", + result->no_user_id); } if ((secret && result->imported != 0) - || (!secret && (result->imported != 0 && result->imported != 1))) { - fprintf(stderr, "Unexpected number of imported keys %i\n", - result->imported); + || (!secret && (result->imported != 0 && result->imported != 1))) { + fprintf(stderr, "Unexpected number of imported keys %i\n", + result->imported); } if (result->imported_rsa != 0) { - fprintf(stderr, "Unexpected number of imported RSA keys %i\n", - result->imported_rsa); + fprintf(stderr, "Unexpected number of imported RSA keys %i\n", + result->imported_rsa); } if ((secret && result->unchanged != 0) - || (!secret && ((result->imported == 0 && result->unchanged != 1) - || (result->imported == 1 && result->unchanged != 0)))) { - fprintf(stderr, "Unexpected number of unchanged keys %i\n", - result->unchanged); + || (!secret && ((result->imported == 0 && result->unchanged != 1) + || (result->imported == 1 && result->unchanged != 0)))) { + fprintf(stderr, "Unexpected number of unchanged keys %i\n", + result->unchanged); } if (result->new_user_ids != 0) { - fprintf(stderr, "Unexpected number of new user IDs %i\n", - result->new_user_ids); + fprintf(stderr, "Unexpected number of new user IDs %i\n", + result->new_user_ids); } if (result->new_sub_keys != 0) { - fprintf(stderr, "Unexpected number of new sub keys %i\n", - result->new_sub_keys); + fprintf(stderr, "Unexpected number of new sub keys %i\n", + result->new_sub_keys); } if ((secret - && ((result->secret_imported == 0 && result->new_signatures != 0) - || (result->secret_imported == 1 && result->new_signatures > 1))) - || (!secret && result->new_signatures != 0)) { - fprintf(stderr, "Unexpected number of new signatures %i\n", - result->new_signatures); - if (result->new_signatures == 2) { - fprintf(stderr, "### ignored due to gpg 1.3.4 problems\n"); - } else { - //exit (1); - } + && ((result->secret_imported == 0 && result->new_signatures != 0) + || (result->secret_imported == 1 && result->new_signatures > 1))) + || (!secret && result->new_signatures != 0)) { + fprintf(stderr, "Unexpected number of new signatures %i\n", + result->new_signatures); + if (result->new_signatures == 2) { + fprintf(stderr, "### ignored due to gpg 1.3.4 problems\n"); + } else { + //exit (1); + } } if (result->new_revocations != 0) { - fprintf(stderr, "Unexpected number of new revocations %i\n", - result->new_revocations); + fprintf(stderr, "Unexpected number of new revocations %i\n", + result->new_revocations); } if ((secret && result->secret_read != 1) - || (!secret && result->secret_read != 0)) { - fprintf(stderr, "Unexpected number of secret keys read %i\n", - result->secret_read); + || (!secret && result->secret_read != 0)) { + fprintf(stderr, "Unexpected number of secret keys read %i\n", + result->secret_read); } if ((secret && result->secret_imported != 0 && result->secret_imported != 1) - || (!secret && result->secret_imported != 0)) { - fprintf(stderr, "Unexpected number of secret keys imported %i\n", - result->secret_imported); + || (!secret && result->secret_imported != 0)) { + fprintf(stderr, "Unexpected number of secret keys imported %i\n", + result->secret_imported); } if ((secret - && ((result->secret_imported == 0 && result->secret_unchanged != 1) - || (result->secret_imported == 1 - && result->secret_unchanged != 0))) - || (!secret && result->secret_unchanged != 0)) { - fprintf(stderr, "Unexpected number of secret keys unchanged %i\n", - result->secret_unchanged); + && ((result->secret_imported == 0 && result->secret_unchanged != 1) + || (result->secret_imported == 1 + && result->secret_unchanged != 0))) + || (!secret && result->secret_unchanged != 0)) { + fprintf(stderr, "Unexpected number of secret keys unchanged %i\n", + result->secret_unchanged); } if (result->not_imported != 0) { - fprintf(stderr, "Unexpected number of secret keys not imported %i\n", - result->not_imported); + fprintf(stderr, "Unexpected number of secret keys not imported %i\n", + result->not_imported); } if (secret) { - if (!result->imports - || (result->imports->next && result->imports->next->next)) { - fprintf(stderr, "Unexpected number of status reports\n"); - } + if (!result->imports + || (result->imports->next && result->imports->next->next)) { + fprintf(stderr, "Unexpected number of status reports\n"); + } } else if (!result->imports || result->imports->next) { fprintf(stderr, "Unexpected number of status reports\n"); } if (strcmp(fpr, result->imports->fpr)) { - fprintf(stderr, "Unexpected fingerprint %s\n", result->imports->fpr); + fprintf(stderr, "Unexpected fingerprint %s\n", result->imports->fpr); } if (result->imports->next && strcmp(fpr, result->imports->next->fpr)) { - fprintf(stderr, "Unexpected fingerprint on second status %s\n", - result->imports->next->fpr); + fprintf(stderr, "Unexpected fingerprint on second status %s\n", + result->imports->next->fpr); } if (result->imports->result != 0) { - fprintf(stderr, "Unexpected status result %s\n", - gpgme_strerror(result->imports->result)); + fprintf(stderr, "Unexpected status result %s\n", + gpgme_strerror(result->imports->result)); } if (secret) { - if (result->secret_imported == 0) { - if (result->imports->status != GPGME_IMPORT_SECRET) { - fprintf(stderr, "Unexpected status %i\n", - result->imports->status); - } - } else if (result->imports->status - != (GPGME_IMPORT_SECRET | GPGME_IMPORT_NEW) - || (result->imports->next - && result->imports->next->status != GPGME_IMPORT_SIG)) { - fprintf(stderr, "Unexpected status %i\n", result->imports->status); - } + if (result->secret_imported == 0) { + if (result->imports->status != GPGME_IMPORT_SECRET) { + fprintf(stderr, "Unexpected status %i\n", + result->imports->status); + } + } else if (result->imports->status + != (GPGME_IMPORT_SECRET | GPGME_IMPORT_NEW) + || (result->imports->next + && result->imports->next->status != GPGME_IMPORT_SIG)) { + fprintf(stderr, "Unexpected status %i\n", result->imports->status); + } } else if ((result->imported == 0 && result->imports->status != 0) - || (result->imported == 1 - && result->imports->status != GPGME_IMPORT_NEW)) { + || (result->imported == 1 + && result->imports->status != GPGME_IMPORT_NEW)) { fprintf(stderr, "Unexpected status %i\n", result->imports->status); } } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv * env, - jobject self, - jlong context, - jlong keydata) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv* env, + jobject self, + jlong context, + jlong keydata) { gpgme_error_t err; gpgme_import_result_t result; - err = gpgme_data_rewind(DATA(keydata)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(keydata)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { - return; + return; } err = gpgme_op_import(CONTEXT(context), DATA(keydata)); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } result = gpgme_op_import_result(CONTEXT(context)); if (result == NULL) { - if (UTILS_onErrorThrowException(env, GPG_ERR_NO_PUBKEY)) - return; + if (UTILS_onErrorThrowException(env, GPG_ERR_NO_PUBKEY)) + return; } else if (result->imported != 1 || result->not_imported != 0) { if (result->imports == NULL) { fprintf(stderr, @@ -774,51 +774,51 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv * env, } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetArmor(JNIEnv * env, - jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetArmor(JNIEnv* env, + jobject self, + jlong context) { return (jlong) gpgme_get_armor(CONTEXT(context)); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetArmor(JNIEnv * env, - jobject self, - jlong context, - jlong armor_state) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetArmor(JNIEnv* env, + jobject self, + jlong context, + jlong armor_state) { gpgme_set_armor(CONTEXT(context), (int) armor_state); } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetTextmode(JNIEnv * env, - jobject self, - jlong context) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetTextmode(JNIEnv* env, + jobject self, + jlong context) { return (jlong) gpgme_get_textmode(CONTEXT(context)); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetTextmode(JNIEnv * env, - jobject self, - jlong context, - jlong mode) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeSetTextmode(JNIEnv* env, + jobject self, + jlong context, + jlong mode) { gpgme_set_textmode(CONTEXT(context), (int) mode); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv * env, - jobject self, - jlong context, - jstring params) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv* env, + jobject self, + jlong context, + jstring params) { gpgme_ctx_t ctx = CONTEXT(context); - char *p; + char* p; gpgme_error_t err; - p = (char *) (*env)->GetStringUTFChars(env, params, NULL); + p = (char*) (*env)->GetStringUTFChars(env, params, NULL); fprintf(stderr, "genKey: \"%s\"\n", p); @@ -827,52 +827,52 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv * env, (*env)->ReleaseStringUTFChars(env, params, p); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv * env, - jobject self, - jlong context, - jstring pattern, - jlong reserved, - jlong keydata) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv* env, + jobject self, + jlong context, + jstring pattern, + jlong reserved, + jlong keydata) { gpgme_ctx_t ctx = CONTEXT(context); - char *p; + char* p; gpgme_data_t data = DATA(keydata); gpgme_error_t err; - p = (char *) (*env)->GetStringUTFChars(env, pattern, NULL); + p = (char*) (*env)->GetStringUTFChars(env, pattern, NULL); err = gpgme_op_export(ctx, p, 0, data); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } (*env)->ReleaseStringUTFChars(env, pattern, p); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv * env, - jobject self, - jlong ctx, - jint proto, - jstring fileName, - jstring homeDir) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv* env, + jobject self, + jlong ctx, + jint proto, + jstring fileName, + jstring homeDir) { gpgme_ctx_t context = CONTEXT(ctx); gpgme_protocol_t protocol = (gpgme_protocol_t) proto; - char *file_name; - char *home_dir; + char* file_name; + char* home_dir; gpgme_error_t err; - file_name = (char *) (*env)->GetStringUTFChars(env, fileName, NULL); - home_dir = (char *) (*env)->GetStringUTFChars(env, homeDir, NULL); + file_name = (char*) (*env)->GetStringUTFChars(env, fileName, NULL); + home_dir = (char*) (*env)->GetStringUTFChars(env, homeDir, NULL); /*fprintf(stderr, "set engine info: proto: %d, fileName: %s, homeDir: %s\n", proto, file_name, home_dir);*/ @@ -882,16 +882,16 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv * env, (*env)->ReleaseStringUTFChars(env, homeDir, home_dir); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } } JNIEXPORT jobject JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult(JNIEnv * env, - jobject self, - jlong ctx) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult(JNIEnv* env, + jobject self, + jlong ctx) { gpgme_ctx_t context = CONTEXT(ctx); @@ -899,39 +899,39 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenkeyResult(JNIEnv * env, jobject resultObj; if (result == NULL) { - return NULL; + return NULL; } //get the right constructor to invoke for every key in result set jclass resultClass; resultClass = - (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGGenkeyResult"); + (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGGenkeyResult"); if (resultClass == NULL) { - return NULL; + return NULL; } jmethodID cid; cid = (*env)->GetMethodID(env, resultClass, "", "()V"); if (cid == NULL) { - return NULL; + return NULL; } resultObj = (*env)->NewObject(env, resultClass, cid); UTILS_setStringMember(env, resultObj, resultClass, "_fpr", result->fpr); UTILS_setBooleanMember(env, resultObj, resultClass, "_primary", - result->primary); + result->primary); UTILS_setBooleanMember(env, resultObj, resultClass, "_sub", result->sub); return resultObj; } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv * env, - jobject self, - jlong ctx, - jlong key, - jboolean allowSecret) +Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv* env, + jobject self, + jlong ctx, + jlong key, + jboolean allowSecret) { gpgme_ctx_t context = CONTEXT(ctx); @@ -943,6 +943,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv * env, err = gpgme_op_delete(context, deletekey, sec); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } } diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 6e5190a..0923273 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -11,47 +11,47 @@ JNIEXPORT jsize JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeSize(JNIEnv * env, jobject self, jlong data) +Java_com_freiheit_gnupg_GnuPGData_gpgmeSize(JNIEnv* env, jobject self, jlong data) { return (jsize) (DATA(data))->data.mem.size; } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem(JNIEnv * env, - jobject self, - jbyteArray plain) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem(JNIEnv* env, + jobject self, + jbyteArray plain) { gpgme_error_t err; - jbyte *plain_ptr = (*env)->GetByteArrayElements(env, plain, NULL); //GETMEM(0) + jbyte* plain_ptr = (*env)->GetByteArrayElements(env, plain, NULL); //GETMEM(0) if (plain_ptr == NULL) { fprintf(stderr, "could not allocate memory.\n"); - return 0; + return 0; } gpgme_data_t data; jlong len = (*env)->GetArrayLength(env, plain); //make private copy of data - err = gpgme_data_new_from_mem(&data, (const char *) plain_ptr, - (size_t) len, 1); + err = gpgme_data_new_from_mem(&data, (const char*) plain_ptr, + (size_t) len, 1); if (UTILS_onErrorThrowException(env, err)) { - return LNG(NULL); + return LNG(NULL); } - (*env)->ReleaseByteArrayElements(env, plain, plain_ptr, 0); //RELMEM(0) + (*env)->ReleaseByteArrayElements(env, plain, plain_ptr, 0); //RELMEM(0) jlong result = LNG(data); return result; } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromFilename(JNIEnv * env, - jobject self, - jstring filename, - jstring mode) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromFilename(JNIEnv* env, + jobject self, + jstring filename, + jstring mode) { - const char *mode_str = (*env)->GetStringUTFChars(env, mode, NULL); - const char *filename_str = (*env)->GetStringUTFChars(env, filename, NULL); + const char* mode_str = (*env)->GetStringUTFChars(env, mode, NULL); + const char* filename_str = (*env)->GetStringUTFChars(env, filename, NULL); if (filename_str == NULL) { fprintf(stderr, "could not allocate memory.\n"); return 0; @@ -72,20 +72,20 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromFilename(JNIEnv * env, } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNew(JNIEnv * env, jobject self) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNew(JNIEnv* env, jobject self) { gpgme_data_t data; gpgme_error_t err = gpgme_data_new(&data); if (UTILS_onErrorThrowException(env, err)) { - return LNG(NULL); + return LNG(NULL); } return LNG(data); } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataWrite(JNIEnv * env, jobject self, - jlong data, jobject out) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataWrite(JNIEnv* env, jobject self, + jlong data, jobject out) { gpgme_error_t err; @@ -95,47 +95,47 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataWrite(JNIEnv * env, jobject self, jclass outputStream = (*env)->GetObjectClass(env, out); if (outputStream == NULL) { fprintf(stderr, "output stream NULL! abort.\n"); - return; + return; } jmethodID writeMethod = - (*env)->GetMethodID(env, outputStream, "write", "([BII)V"); + (*env)->GetMethodID(env, outputStream, "write", "([BII)V"); if (writeMethod == NULL) { fprintf(stderr, "write method NULL! abort.\n"); - return; + return; } jbyteArray jbuf; err = (gpgme_data_seek ( DATA(data), (off_t)0, SEEK_SET ) < 0); if (UTILS_onErrorThrowException(env, err)) { - fprintf(stderr, "error throw exception! abort.\n"); - return; + fprintf(stderr, "error throw exception! abort.\n"); + return; } int size = 0; while ((nread = gpgme_data_read(DATA(data), buf, BUFSIZE)) != 0) { size += nread; - jbuf = (*env)->NewByteArray(env, nread); - if (jbuf == NULL) { - fprintf(stderr, "jbuf is NULL! abort.\n"); - return; - } - (*env)->SetByteArrayRegion(env, jbuf, 0, nread, buf); - (*env)->CallVoidMethod(env, out, writeMethod, jbuf, (jint)0, - (jint)nread); - if ((*env)->ExceptionCheck(env)) { - (*env)->DeleteLocalRef(env, jbuf); - return; - } - (*env)->DeleteLocalRef(env, jbuf); + jbuf = (*env)->NewByteArray(env, nread); + if (jbuf == NULL) { + fprintf(stderr, "jbuf is NULL! abort.\n"); + return; + } + (*env)->SetByteArrayRegion(env, jbuf, 0, nread, buf); + (*env)->CallVoidMethod(env, out, writeMethod, jbuf, (jint)0, + (jint)nread); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, jbuf); + return; + } + (*env)->DeleteLocalRef(env, jbuf); } } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRelease(JNIEnv * env, jobject self, - jlong data) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRelease(JNIEnv* env, jobject self, + jlong data) { gpgme_data_t dh = DATA(data); if (dh->data.stream != NULL) @@ -144,48 +144,48 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRelease(JNIEnv * env, jobject self, } JNIEXPORT void JNICALL -Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv * env, jobject self, - jlong data, jobject in) +Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv* env, jobject self, + jlong data, jobject in) { gpgme_error_t err; jclass inputStream = (*env)->GetObjectClass(env, in); if (inputStream == NULL) { fprintf(stderr, "input stream NULL! abort.\n"); - return; + return; } jmethodID readMethod = (*env)->GetMethodID(env, inputStream, - "read", "([BII)I"); + "read", "([BII)I"); if (readMethod == NULL) { fprintf(stderr, "read method NULL! abort.\n"); - return; + return; } - jbyteArray jbuf = (*env)->NewByteArray(env, BUFSIZE); //GETMEM(0) + jbyteArray jbuf = (*env)->NewByteArray(env, BUFSIZE); //GETMEM(0) jlong nread; err = (gpgme_data_seek (DATA(data), (off_t)0, SEEK_SET) < 0); if (UTILS_onErrorThrowException(env, err)) { - return; + return; } ssize_t written; while ((nread = (*env)->CallIntMethod(env, in, readMethod, - jbuf, (jint)0, BUFSIZE)) != -1) { + jbuf, (jint)0, BUFSIZE)) != -1) { - jbyte *buf = (*env)->GetByteArrayElements(env, jbuf, NULL); - if (buf == NULL) { - return; - } + jbyte* buf = (*env)->GetByteArrayElements(env, jbuf, NULL); + if (buf == NULL) { + return; + } - written = gpgme_data_write(DATA(data), buf, nread); - if ((*env)->ExceptionCheck(env)) { - (*env)->DeleteLocalRef(env, jbuf); - return; - } + written = gpgme_data_write(DATA(data), buf, nread); + if ((*env)->ExceptionCheck(env)) { + (*env)->DeleteLocalRef(env, jbuf); + return; + } } - (*env)->DeleteLocalRef(env, jbuf); //RELMEM(0) + (*env)->DeleteLocalRef(env, jbuf); //RELMEM(0) } diff --git a/jni/GnuPGGenkeyResult.c b/jni/GnuPGGenkeyResult.c index 6bcf72a..b10c45e 100644 --- a/jni/GnuPGGenkeyResult.c +++ b/jni/GnuPGGenkeyResult.c @@ -6,26 +6,26 @@ #include JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetFpr(JNIEnv * env, - jobject self, - jlong result) +Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetFpr(JNIEnv* env, + jobject self, + jlong result) { jstring str = (*env)->NewStringUTF(env, (GENKEYRESULT(result))->fpr); return str; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetPrimary(JNIEnv * env, - jobject self, - jlong result) +Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetPrimary(JNIEnv* env, + jobject self, + jlong result) { return (GENKEYRESULT(result))->primary; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetSub(JNIEnv * env, - jobject self, - jlong result) +Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetSub(JNIEnv* env, + jobject self, + jlong result) { return (GENKEYRESULT(result))->primary; } diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index 08cb09a..d13b6e1 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -7,17 +7,17 @@ JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKey(JNIEnv * env, jobject self, - jlong context, jstring fingerprint, - jboolean secret) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKey(JNIEnv* env, jobject self, + jlong context, jstring fingerprint, + jboolean secret) { gpgme_key_t key; - const char *fpr = (*env)->GetStringUTFChars(env, fingerprint, NULL); + const char* fpr = (*env)->GetStringUTFChars(env, fingerprint, NULL); gpgme_error_t err = gpgme_get_key(CONTEXT(context), fpr, &key, secret); if (UTILS_onErrorThrowException(env, err)) { - (*env)->ReleaseStringUTFChars(env, fingerprint, fpr); - return LNG(NULL); + (*env)->ReleaseStringUTFChars(env, fingerprint, fpr); + return LNG(NULL); } (*env)->ReleaseStringUTFChars(env, fingerprint, fpr); @@ -27,145 +27,145 @@ Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKey(JNIEnv * env, jobject self, } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeKeyUnref(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeKeyUnref(JNIEnv* env, jobject self, + jlong key) { gpgme_key_unref(KEY(key)); return 0l; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetName(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetName(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->uids->name); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetEmail(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetEmail(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->uids->email); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKeyID(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetKeyID(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->subkeys->keyid); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetFingerprint(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetFingerprint(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->subkeys->fpr); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetComment(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetComment(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->uids->comment); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetUserID(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetUserID(JNIEnv* env, jobject self, + jlong key) { jstring str = (*env)->NewStringUTF(env, (KEY(key))->uids->uid); return str; } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetSignature(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeGetSignature(JNIEnv* env, jobject self, + jlong key) { return LNG((KEY(key))->uids->signatures); } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanEncrypt(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanEncrypt(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->can_encrypt; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanSign(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanSign(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->can_sign; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanCerify(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanCerify(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->can_certify; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanAuthenticate(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeCanAuthenticate(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->can_authenticate; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsRevoked(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsRevoked(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->revoked; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsExpired(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsExpired(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->expired; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsDisabled(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsDisabled(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->disabled; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsInvalid(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsInvalid(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->invalid; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsQualified(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsQualified(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->is_qualified; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsSecret(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeIsSecret(JNIEnv* env, jobject self, + jlong key) { return (KEY(key))->secret; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGKey_gpgmeHasSecretKey(JNIEnv * env, jobject self, - jlong key) +Java_com_freiheit_gnupg_GnuPGKey_gpgmeHasSecretKey(JNIEnv* env, jobject self, + jlong key) { jboolean hasSecretKey = 0; gpgme_subkey_t subkey; - for(subkey = KEY(key)->subkeys; subkey; subkey = subkey->next) + for (subkey = KEY(key)->subkeys; subkey; subkey = subkey->next) if (subkey->secret) return 1; return 0; diff --git a/jni/GnuPGSignature.c b/jni/GnuPGSignature.c index 3ca7a9d..a3e3c68 100644 --- a/jni/GnuPGSignature.c +++ b/jni/GnuPGSignature.c @@ -6,78 +6,78 @@ #include JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetRevoked(JNIEnv * env, - jobject self, jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetRevoked(JNIEnv* env, + jobject self, jlong sig) { return (jboolean) (KEYSIG(sig))->revoked; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExpired(JNIEnv * env, - jobject self, jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExpired(JNIEnv* env, + jobject self, jlong sig) { return (jboolean) (KEYSIG(sig))->expired; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetInvalid(JNIEnv * env, - jobject self, jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetInvalid(JNIEnv* env, + jobject self, jlong sig) { return (jboolean) (KEYSIG(sig))->invalid; } JNIEXPORT jboolean JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExportable(JNIEnv * env, - jobject self, - jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExportable(JNIEnv* env, + jobject self, + jlong sig) { return (jboolean) (KEYSIG(sig))->exportable; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetKeyID(JNIEnv * env, jobject self, - jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetKeyID(JNIEnv* env, jobject self, + jlong sig) { jstring str = (*env)->NewStringUTF(env, (KEYSIG(sig))->keyid); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetUserID(JNIEnv * env, - jobject self, jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetUserID(JNIEnv* env, + jobject self, jlong sig) { jstring str = (*env)->NewStringUTF(env, (KEYSIG(sig))->uid); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetName(JNIEnv * env, jobject self, - jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetName(JNIEnv* env, jobject self, + jlong sig) { jstring str = (*env)->NewStringUTF(env, (KEYSIG(sig))->name); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetEmail(JNIEnv * env, jobject self, - jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetEmail(JNIEnv* env, jobject self, + jlong sig) { jstring str = (*env)->NewStringUTF(env, (KEYSIG(sig))->email); return str; } JNIEXPORT jstring JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetComment(JNIEnv * env, - jobject self, jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetComment(JNIEnv* env, + jobject self, jlong sig) { jstring str = (*env)->NewStringUTF(env, (KEYSIG(sig))->comment); return str; } JNIEXPORT jlong JNICALL -Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetNextSignature(JNIEnv * env, - jobject self, - jlong sig) +Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetNextSignature(JNIEnv* env, + jobject self, + jlong sig) { return LNG((KEYSIG(sig))->next); } diff --git a/jni/gpgmeutils.c b/jni/gpgmeutils.c index 2592534..bc7270b 100644 --- a/jni/gpgmeutils.c +++ b/jni/gpgmeutils.c @@ -4,27 +4,27 @@ #define BUF_LEN 1024 jboolean -UTILS_setStringMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, const char *fieldvalue) +UTILS_setStringMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, const char* fieldvalue) { //get the field from the class jfieldID fld = - (*env)->GetFieldID(env, selfclass, fieldname, "Ljava/lang/String;"); + (*env)->GetFieldID(env, selfclass, fieldname, "Ljava/lang/String;"); if (fld == NULL) { - return JNI_FALSE; + return JNI_FALSE; } jstring jval = (*env)->NewStringUTF(env, fieldvalue); if (jval == NULL) { - return JNI_FALSE; + return JNI_FALSE; } (*env)->SetObjectField(env, self, fld, jval); return JNI_TRUE; } jboolean -UTILS_setIntMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, int fieldvalue) +UTILS_setIntMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, int fieldvalue) { //get the field from the class @@ -32,19 +32,19 @@ UTILS_setIntMember(JNIEnv * env, jobject self, jclass selfclass, jfieldID fld = (*env)->GetFieldID(env, selfclass, fieldname, "I"); if (fld == NULL) { - return JNI_FALSE; + return JNI_FALSE; } if (jval == 0) { - return JNI_FALSE; + return JNI_FALSE; } (*env)->SetIntField(env, self, fld, jval); return JNI_TRUE; } void -UTILS_setBooleanMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, unsigned int fieldvalue) +UTILS_setBooleanMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, unsigned int fieldvalue) { //get the field from the class @@ -52,55 +52,55 @@ UTILS_setBooleanMember(JNIEnv * env, jobject self, jclass selfclass, jfieldID fld = (*env)->GetFieldID(env, selfclass, fieldname, "Z"); if (fld == NULL) { - return; + return; } if (jval == 0) { - return; + return; } (*env)->SetBooleanField(env, self, fld, jval); } -jboolean UTILS_onErrorThrowException(JNIEnv * env, gpgme_error_t err) +jboolean UTILS_onErrorThrowException(JNIEnv* env, gpgme_error_t err) { if (err) { - char exceptionString[BUF_LEN]; /* this is enough */ - int spaceUsed; - jclass exception = - (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGException"); - - if (exception == NULL) { - return JNI_TRUE; - } - spaceUsed = snprintf(exceptionString, BUF_LEN, "%u: ", err); - gpgme_strerror_r(err, exceptionString + spaceUsed, BUF_LEN - spaceUsed); - (*env)->ThrowNew(env, exception, exceptionString); - (*env)->DeleteLocalRef(env, exception); - return JNI_TRUE; + char exceptionString[BUF_LEN]; /* this is enough */ + int spaceUsed; + jclass exception = + (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGException"); + + if (exception == NULL) { + return JNI_TRUE; + } + spaceUsed = snprintf(exceptionString, BUF_LEN, "%u: ", err); + gpgme_strerror_r(err, exceptionString + spaceUsed, BUF_LEN - spaceUsed); + (*env)->ThrowNew(env, exception, exceptionString); + (*env)->DeleteLocalRef(env, exception); + return JNI_TRUE; } else { - return JNI_FALSE; + return JNI_FALSE; } } int -UTILS_copyRecipientsFromJvm(JNIEnv * env, jlongArray recipients, - gpgme_key_t keys[]) +UTILS_copyRecipientsFromJvm(JNIEnv* env, jlongArray recipients, + gpgme_key_t keys[]) { //how many keys from recipients did we receive? jsize len = (*env)->GetArrayLength(env, recipients); if (len < 1) { - return len; + return len; } //allocate native memory from recipient keys - jlong *carr = (*env)->GetLongArrayElements(env, recipients, NULL); + jlong* carr = (*env)->GetLongArrayElements(env, recipients, NULL); if (carr == NULL) { - return -1; + return -1; } //copy recipient keys to new array... int i; for (i = 0; i < len; i++) { - keys[i] = KEY(carr[i]); + keys[i] = KEY(carr[i]); } //and mark the end of the array with a NULL. keys[len] = NULL; diff --git a/jni/gpgmeutils.h b/jni/gpgmeutils.h index 4f66b34..25a81ad 100644 --- a/jni/gpgmeutils.h +++ b/jni/gpgmeutils.h @@ -5,18 +5,18 @@ #include #include -jboolean UTILS_setStringMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, const char *fieldvalue); +jboolean UTILS_setStringMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, const char* fieldvalue); -jboolean UTILS_setIntMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, int fieldvalue); +jboolean UTILS_setIntMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, int fieldvalue); -void UTILS_setBooleanMember(JNIEnv * env, jobject self, jclass selfclass, - const char *fieldname, unsigned int fieldvalue); +void UTILS_setBooleanMember(JNIEnv* env, jobject self, jclass selfclass, + const char* fieldname, unsigned int fieldvalue); -jboolean UTILS_onErrorThrowException(JNIEnv * env, gpgme_error_t err); +jboolean UTILS_onErrorThrowException(JNIEnv* env, gpgme_error_t err); -int UTILS_copyRecipientsFromJvm(JNIEnv * env, jlongArray recipients, gpgme_key_t keys[]); +int UTILS_copyRecipientsFromJvm(JNIEnv* env, jlongArray recipients, gpgme_key_t keys[]); /* use this macro to convert a jlong variable to a pointer to a gpgme context in a safe and portable way */ #define CONTEXT(c) ((gpgme_ctx_t)_ptrFromJLong(c)) @@ -33,13 +33,13 @@ int UTILS_copyRecipientsFromJvm(JNIEnv * env, jlongArray recipients, gpgme_key_t #define LNG(a) (_jlongFromPtr(a)) // don't use this directly, it is wrapped by the PTR() macro -inline static void *_ptrFromJLong(jlong l) +inline static void* _ptrFromJLong(jlong l) { - return (void *) (unsigned long) l; + return (void*) (unsigned long) l; } // don't use this directly, it is wrapped by the PTR() macro -inline static jlong _jlongFromPtr(void *p) +inline static jlong _jlongFromPtr(void* p) { return (jlong) (unsigned long) p; } From 174f61140c2299c3c7ad2673563e44a93822fc06 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 7 Dec 2013 00:53:56 -0500 Subject: [PATCH 46/90] POSIX setenv() to change app's env vars, which GnuPG requires This allows GPG to set the env vars at app launch, and everything should magically get the env. There are two things that require setting env vars: * Android's linker can only find shared libs by looking in LD_LIBRARY_PATH, so in order for the GnuPG command line tools to find the required shared libraries, LD_LIBRARY_PATH needs to include the apps lib paths also. * GnuPG needs env vars like GNUPGHOME to find the folder where keyrings, UNIX sockets, and config files are kept. http://stackoverflow.com/questions/318239/how-do-i-set-environment-variables-from-java refs #1548 --- jni/GnuPGContext.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index f40f83c..5b1dd8c 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -91,16 +91,6 @@ JNI_OnLoad(JavaVM* vm, void* reserved) { _jvm = vm; -#ifdef __ANDROID__ - // TODO get the actual gpgAppOpt path from Java - // we need to set LD_LIBRARY_PATH because gpgme calls the cmd line utils - const char* ldLibraryPath = getenv("LD_LIBRARY_PATH"); - const char* gpgAppOpt = "/data/data/info.guardianproject.gpg/app_opt/lib"; - size_t newPathLen = strlen(ldLibraryPath) + strlen(gpgAppOpt) + 2; - char newPath[newPathLen]; - snprintf(newPath, newPathLen, "%s:%s", gpgAppOpt, ldLibraryPath); - setenv("LD_LIBRARY_PATH", newPath, 1); -#endif /* __ANDROID */ // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); const char* version = gpgme_check_version(NULL); From 59d4f530d01730a1be4473eb90bf3400e6e990d0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 11 Dec 2013 12:56:48 -0500 Subject: [PATCH 47/90] add changePassphrase() and purge old non-functional code gnupg-for-java was written for GnuPG 1.x with GPGME. The expectation there was that the passphrase prompt was handled by the client app. Now in GnuPG 2.x, all passphrase prompting is handled by GnuPG pinentry, which is always triggered by gpg-agent. This commit hooks up the current function to trigger the passphrase change, and removes the old dead code for GnuPG 1.x closes #1585 --- jni/GnuPGContext.c | 102 +---------------------- src/com/freiheit/gnupg/GnuPGContext.java | 25 ------ 2 files changed, 1 insertion(+), 126 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 5b1dd8c..f10d8c4 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -18,73 +18,6 @@ JavaVM* _jvm; -void* passphrase_cb = NULL; - -/* -gpgme_error_t -passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, - int prev_was_bad, int fd) -{ - jobject self = (jobject) hook; - - if (self == NULL) { - return GPG_ERR_GENERAL; - } - - JNIEnv *env; - (*_jvm)->AttachCurrentThread(_jvm, &env, NULL); - - jclass cls = (*env)->GetObjectClass(env, self); - - if (cls == NULL) { - return GPG_ERR_GENERAL; - } - - char methodDescr[] = - "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"; - jmethodID mid = - (*env)->GetMethodID(env, cls, "passphraseCallback", methodDescr); - - if (mid == NULL) { - return GPG_ERR_GENERAL; - } - - //jbyte *hint = (*env)->NewStringUTF(env, uid_hint); - jstring hint = (*env)->NewStringUTF(env, uid_hint); - if (hint == NULL) { - return GPG_ERR_GENERAL; - } - - jstring pphrinfo = (*env)->NewStringUTF(env, passphrase_info); - if (pphrinfo == NULL) { - return GPG_ERR_GENERAL; - } - - //jbyte *pphr;//passphrase is return value from callback to Java - jstring pphr; //passphrase is return value from callback to Java - pphr = (*env)->CallObjectMethod(env, self, mid, hint, pphrinfo, (jlong)0); - - if (pphr == NULL) { - return GPG_ERR_CANCELED; - } - - int len = (*env)->GetStringLength(env, pphr); - char buf[len + 1]; //leave the last char for newline - - //TODO: Check for errors after the next call?! - (*env)->GetStringUTFRegion(env, pphr, 0, len, buf); - - buf[len] = '\n'; //add the newline to the end... - - ssize_t written; - written = write(fd, buf, len); - if (written == -1) { - return GPG_ERR_GENERAL; - } - - return GPG_ERR_NO_ERROR; -} -*/ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) @@ -190,8 +123,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv* env, { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void*)self); - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; @@ -279,33 +210,10 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpChangePassphrase(JNIEnv* env, { gpgme_error_t err; - gpgme_data_t out = NULL; - - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - - err = gpgme_data_new(&out); + err = gpgme_op_passwd(CONTEXT(context), KEY(keydata), 0); if (UTILS_onErrorThrowException(env, err)) { return; } - - err = gpgme_op_edit(CONTEXT(context), KEY(keydata), edit_fnc, out, out); - if (UTILS_onErrorThrowException(env, err)) { - return; - } - - fputs("[-- Last response --]\n", stdout); - flush_data(out); - - gpgme_data_release(out); - - /* err = gpgme_op_decrypt_start(CONTEXT(context), (gpgme_data_t)cipher, (gpgme_data_t)plain); */ - /* if(UTILS_onErrorThrowException(env, err)){ */ - /* return; */ - /* } */ - /* gpgme_ctx_t waitedOn = gpgme_wait(CONTEXT(context), err, 1);//HANG UNTIL COMPLETED! */ - /* if(waitedOn != NULL && UTILS_onErrorThrowException(env, err)){ */ - /* return; */ - /* } */ } JNIEXPORT void JNICALL @@ -326,8 +234,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv* env, { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - jsize len = (*env)->GetArrayLength(env, recipients); gpgme_key_t keys[len + 1]; if (UTILS_copyRecipientsFromJvm(env, recipients, keys) < 1) { @@ -369,8 +275,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv* env, { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; @@ -404,8 +308,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpSign(JNIEnv* env, { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, (void*) self); - err = gpgme_data_rewind(DATA(plain)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; @@ -443,8 +345,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpVerify(JNIEnv* env, { gpgme_error_t err; - gpgme_set_passphrase_cb(CONTEXT(context), passphrase_cb, self); - err = gpgme_data_rewind(DATA(signature)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index bc959f6..9b18411 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -171,28 +171,6 @@ public void setTextmode(boolean state) { gpgmeSetTextmode(getInternalRepresentation(), state); } - /** - * Sets a listener, if GPGME needs to request a passphrase from the user (or - * even from a program or a database..) - *

- * A passphrase-listener is global to a jvm. This means, you can register - * only one listener. - *

- * I am working on this, but it is not so easy to access jvm methods from a - * specific object from a non-jvm thread, which the passphrase callback - * is... - * - * @param l a GnuPGPassphraseListener implementation - * @see com.freiheit.gnupg.GnuPGPassphraseListener - */ - public void setPassphraseListener(GnuPGPassphraseListener l) { - _passphraseListener = l; - } - - public String passphraseCallback(String hint, String passphraseInfo, long wasBad) { - return _passphraseListener.getPassphrase(hint, passphraseInfo, wasBad); - } - private long[] getInternalRepresentationFromRecipients(GnuPGKey[] recipients) { // note that these are pointers to addresses in the gnupg-for-java // shared lib @@ -643,9 +621,6 @@ public void decryptVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGExcepti } public void changePassphrase(GnuPGKey key) throws GnuPGException { - if (_passphraseListener == null) - throw new GnuPGException("Aborting: No GnuPGPassphraseListener set."); - if (key == null) return; From f8bd42f3f1ac5aa1859fc595930ca60cf10cffa8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 13 Dec 2013 16:15:30 -0500 Subject: [PATCH 48/90] replace crazy loops with linked list when building keylists The old code was buggy and difficult to read. This commit replaces it with one pass of reading keys from gpgme and writing to a linked list. Then a second pass that creates a fixed java Array and fills it from the linked list. closes #1660, closes #1621 --- jni/GnuPGContext.c | 97 ++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index f10d8c4..046030c 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -15,6 +15,7 @@ #include #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "GnuPGContext", __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "GnuPGContext", __VA_ARGS__) JavaVM* _jvm; @@ -382,17 +383,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, jstring query, jboolean secret_only) { - gpgme_error_t err; - gpgme_key_t key; - jlong num_keys_found = 0; - jobjectArray result = NULL; - jobject keyObj = NULL; - //copy string object from java to native string const jsize query_len = (*env)->GetStringLength(env, query); LOGD("query length %d\n", query_len); const jbyte* query_str = (jbyte*)(*env)->GetStringUTFChars(env, query, - NULL); + NULL); //get the right constructor to invoke for every key in result set jclass keyClass; keyClass = (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGKey"); @@ -405,48 +400,56 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, if (cid == NULL) { return NULL; } - //loop two times: one for counting, second for generating result array - int is_counting = 0; //loop 1: counting number of keys in result - int is_working = 1; //loop 2: generating result array - - int i = 0; //loop counter - int j = 0; //index in result array, used only in second loop run... - for (i = 0; i < 2; i++) { //loops [0..1] - err = gpgme_op_keylist_start(CONTEXT(context), - query_len > 0 ? (const char*)query_str : NULL, - secret_only); - if (UTILS_onErrorThrowException(env, err)) { - (*env)->ReleaseStringUTFChars(env, query, (const char*)query_str); - return NULL; - } - - while (!err) { - err = gpgme_op_keylist_next(CONTEXT(context), &key); - if ((gpg_err_code(err) != GPG_ERR_EOF) - && UTILS_onErrorThrowException(env, err)) { - return NULL; - } - if (is_counting == i && key != NULL) { //only true in first loop: i=0 - num_keys_found++; //increment result count - gpgme_key_release(key); - } else if (is_working == i && key != NULL) { //only true in second loop: i=1 - if (result == NULL) { - result = (*env)->NewObjectArray(env, - num_keys_found, - keyClass, - NULL); - } - keyObj = (*env)->NewObject(env, keyClass, cid, LNG(key)); - (*env)->SetObjectArrayElement(env, result, j++, keyObj); - } else { - //FIXME: Can not happen...but should be checked -> throwing exception? - } - key = NULL; - - } //end while + gpgme_error_t err = gpgme_op_keylist_start(CONTEXT(context), + query_len > 0 ? (const char*)query_str : NULL, + secret_only); + if (UTILS_onErrorThrowException(env, err)) { + (*env)->ReleaseStringUTFChars(env, query, (const char*)query_str); + LOGD("keylist gpgme error 1: %s\n", gpgme_strerror(err)); + return NULL; + } - } //end for + gpgme_key_t key; + jlong num_keys_found = 0; + struct _keyInList { + gpgme_key_t key; + struct _keyInList *next; + }; + typedef struct _keyInList *keyInList; + keyInList current, next, head = NULL; + while (!err) { + err = gpgme_op_keylist_next(CONTEXT(context), &key); + if ((gpg_err_code(err) != GPG_ERR_EOF) + && UTILS_onErrorThrowException(env, err)) { + LOGD("keylist gpgme error: %s\n", gpgme_strerror(err)); + return NULL; + } else if (err) { + break; // we have nothing, quit before setting the list + } + current = (keyInList)malloc(sizeof(keyInList)); + current->key = key; + current->next = head; + head = current; + LOGD("Add key %i: (%s <%s>)", + (int)num_keys_found, key->uids->name, key->uids->email); + num_keys_found++; + } + current = head; + jobject keyObj = NULL; + jobjectArray result = (*env)->NewObjectArray(env, + num_keys_found, + keyClass, + NULL); + int i; + for(i = 0; i < num_keys_found; i++) { + key = current->key; + keyObj = (*env)->NewObject(env, keyClass, cid, LNG(key)); + (*env)->SetObjectArrayElement(env, result, i, keyObj); + next = current->next; + free(current); + current = next; + } //..and release the query string for gc.. (*env)->ReleaseStringUTFChars(env, query, (const char*) query_str); From 2a60215fd16bc257c96353bd95fc689a27caa560 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 17 Jan 2014 11:38:32 -0500 Subject: [PATCH 49/90] purge dead passphrase code In GnuPG 2.x, gpg-agent handles launching pinentry for getting the passphrase from the user, so there is no use for Java/JNI code for doing it since it can't be set up that way anymore. refs #1585 --- src/com/freiheit/gnupg/GnuPGContext.java | 27 --------- .../gnupg/GnuPGPassphraseConsole.java | 56 ------------------- .../gnupg/GnuPGPassphraseListener.java | 41 -------------- 3 files changed, 124 deletions(-) delete mode 100644 src/com/freiheit/gnupg/GnuPGPassphraseConsole.java delete mode 100644 src/com/freiheit/gnupg/GnuPGPassphraseListener.java diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 9b18411..5854aa8 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -35,32 +35,6 @@ * } * * - * If you execute an operation, where GnuPG needs a passphrase (password, - * mantra) from you, you need to tell the library which Class is listening for - * such a request and is able to deliver the entered passphrase to the library. - * You can implement such a listener by yourself, but you can also use two - * pre-fabricated ones. (Of course, normally you should install - * gpg-agent/pinentry for this job...but some will need this ability to get - * passphrases from a database or so. And: This release is not checking for the - * existence of gpg-agent...so it won't work anyway.) - *

- * How to add a Passphrase-Listener to read a password from the console? - * - *

- *    {@code
- *      ctx.setPassphraseListener(new GnuPGPassphraseConsole());
- *      //caution: you can still see the password while you are typing...
- *    }
- * 
- * - * How to add a Passphrase-Listener to read a password from the swing dialog? - * - *
- *    {@code
- *      ctx.setPassphraseListener(new GnuPGPassphraseWindow());
- *    }
- * 
- * * @author Stefan Richter, stefan@freiheit.com */ @@ -74,7 +48,6 @@ public class GnuPGContext extends GnuPGPeer { private String _filename; private String _reqversion; private int _protocol; - private GnuPGPassphraseListener _passphraseListener = null; /** Creates a new Context (use on context for one thread!) */ public GnuPGContext() { diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java b/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java deleted file mode 100644 index 0904a18..0000000 --- a/src/com/freiheit/gnupg/GnuPGPassphraseConsole.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: GnuPGPassphraseConsole.java,v 1.1 2005/01/24 13:56:58 stefan Exp $ - * (c) Copyright 2005 freiheit.com technologies gmbh, Germany. - * - * This file is part of Java for GnuPG (http://www.freiheit.com). - * - * Java for GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * Please see COPYING for the complete licence. - */ - -package com.freiheit.gnupg; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -/** - * Requests a passphrase for a crypto operation from the command line. This is - * triggered by gpgme. You must register this as a listener to the GnuPGContext. - * It stills echoes the passphrase on the console. Remember, this is an alpha - * release... - * - * @see com.freiheit.gnupg.GnuPGContext - * @author Stefan Richter, stefan@freiheit.com - */ -public class GnuPGPassphraseConsole implements GnuPGPassphraseListener { - private BufferedReader _reader; - - /** - * Default-Constructor. - */ - public GnuPGPassphraseConsole() { - _reader = new BufferedReader(new InputStreamReader(System.in)); - } - - /** - * Prints to the console, asks for the passphrase and returns it to gpgme. - */ - public String getPassphrase(String hint, String passphraseInfo, long wasBad) { - StringBuffer prompt = new StringBuffer("Enter GnuPG Passphrase ("); - prompt.append(hint).append("): "); - System.out.print(prompt.toString()); - String line = null; - try { - line = _reader.readLine(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - return line; - } -} diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java b/src/com/freiheit/gnupg/GnuPGPassphraseListener.java deleted file mode 100644 index 2aa896b..0000000 --- a/src/com/freiheit/gnupg/GnuPGPassphraseListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * $Id: GnuPGPassphraseListener.java,v 1.1 2005/01/24 13:56:58 stefan Exp $ - * (c) Copyright 2005 freiheit.com technologies gmbh, Germany. - * - * This file is part of Java for GnuPG (http://www.freiheit.com). - * - * Java for GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * Please see COPYING for the complete licence. - */ - -package com.freiheit.gnupg; - -/** - * This is the listener interface you need to implement, if you want to react to - * the passphrase callbacks of the gpgme library for yourself. In this way, you - * can for example lookup passphrases from a database or so and return them to - * gpgme. There are also two pre-fabricated listener. - * - * @see com.freiheit.gnupg.GnuPGPassphraseWindow - * @see com.freiheit.gnupg.GnuPGPassphraseConsole - * @author Stefan Richter, stefan@freiheit.com - */ -public interface GnuPGPassphraseListener { - /** - * This method will be called by gpgme, if a passphrase is necessary to - * complete a crypto operation. Implement this interface and register it - * with the GnuPGContext on which you are operating. - * - * @param hint TODO - * @param passphraseInfo TODO - * @param wasBad TODO - * @return passphrase to be supplied to gpgme callback (MUST include a \n at - * the end of the string) - * @see com.freiheit.gnupg.GnuPGContext - */ - public String getPassphrase(String hint, String passphraseInfo, long wasBad); -} From 3d4d40f6162b5280c5896e9bb97fee1826e9e86d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:06:00 -0400 Subject: [PATCH 50/90] ignore generated JNI headers --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a37b0a5..5242b20 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ dist/ hs_err_pid*.log jni/*.o jni/*.orig +# generated JNI headers +jni/com_freiheit_gnupg_GnuPG*.h lib/libgnupg-for-java.so From b24e3b5a7144b5f9a34c9d38a62da35ceb5875a5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:06:40 -0400 Subject: [PATCH 51/90] add Eclipse project to make it easier to get started --- .classpath | 8 ++++++++ .project | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 .classpath create mode 100644 .project diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..2d3c2eb --- /dev/null +++ b/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..063aec5 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + gnupg-for-java + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + From 35140b059881cfcf78f55e42f7931fa58e285a8a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:07:48 -0400 Subject: [PATCH 52/90] purge Android-specific logging code --- jni/GnuPGContext.c | 10 ---------- src/com/freiheit/gnupg/GnuPGContext.java | 4 +--- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 046030c..d82a1d9 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -12,11 +12,6 @@ #include "gpgmeutils.h" -#include - -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "GnuPGContext", __VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "GnuPGContext", __VA_ARGS__) - JavaVM* _jvm; @@ -385,7 +380,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, { //copy string object from java to native string const jsize query_len = (*env)->GetStringLength(env, query); - LOGD("query length %d\n", query_len); const jbyte* query_str = (jbyte*)(*env)->GetStringUTFChars(env, query, NULL); //get the right constructor to invoke for every key in result set @@ -406,7 +400,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, secret_only); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, query, (const char*)query_str); - LOGD("keylist gpgme error 1: %s\n", gpgme_strerror(err)); return NULL; } @@ -422,7 +415,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, err = gpgme_op_keylist_next(CONTEXT(context), &key); if ((gpg_err_code(err) != GPG_ERR_EOF) && UTILS_onErrorThrowException(env, err)) { - LOGD("keylist gpgme error: %s\n", gpgme_strerror(err)); return NULL; } else if (err) { break; // we have nothing, quit before setting the list @@ -431,8 +423,6 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, current->key = key; current->next = head; head = current; - LOGD("Add key %i: (%s <%s>)", - (int)num_keys_found, key->uids->name, key->uids->email); num_keys_found++; } current = head; diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index 5854aa8..bee5207 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -19,8 +19,6 @@ import java.io.File; import java.io.IOException; -import android.util.Log; - /** * Start here, because for all operations, you first need to create a * GnuPGContext. Use one context object for every single thread or (really) take @@ -703,7 +701,7 @@ public void importKey(GnuPGData keydata) throws GnuPGException { public void importKey(File file) throws GnuPGException, IOException { GnuPGData keydata = createDataObject(file); if (keydata == null) { - Log.e(TAG, "importkey: parsing key data failed"); + System.out.println("importkey: parsing key data failed"); return; } gpgmeOpImport(getInternalRepresentation(), keydata.getInternalRepresentation()); From 09bc751411fac9300b9d34727cccc82b335b5c60 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:12:36 -0400 Subject: [PATCH 53/90] add jar path to runTests.sh --- runTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runTests.sh b/runTests.sh index deb9dec..a4d8b91 100755 --- a/runTests.sh +++ b/runTests.sh @@ -1,4 +1,4 @@ #STYLE=textui STYLE=swingui #STYLE=awtui -java -Djava.library.path=`pwd`/jni -cp build/jar/gnupg-for-java-0.1.6.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.tests.GnuPGTestSuite +java -Djava.library.path=`pwd`/jni:`pwd`/lib -cp build/jar/gnupg-for-java-0.1.6.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.tests.GnuPGTestSuite From dd23cc11780ad5d8b575e2f03f304e6ee4796de8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:34:22 -0400 Subject: [PATCH 54/90] purge unused variables --- jni/GnuPGContext.c | 1 - jni/GnuPGKey.c | 1 - 2 files changed, 2 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index d82a1d9..cf92ed4 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -22,7 +22,6 @@ JNI_OnLoad(JavaVM* vm, void* reserved) // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); - const char* version = gpgme_check_version(NULL); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); #ifdef LC_MESSAGES gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index d13b6e1..84eb9c4 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -163,7 +163,6 @@ JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGKey_gpgmeHasSecretKey(JNIEnv* env, jobject self, jlong key) { - jboolean hasSecretKey = 0; gpgme_subkey_t subkey; for (subkey = KEY(key)->subkeys; subkey; subkey = subkey->next) if (subkey->secret) From 0cb77d5137ccc86a6c86f0e9777917438812d721 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Mar 2014 20:36:43 -0400 Subject: [PATCH 55/90] include gpgme source for context.h This should go away once gpgme_signers_count() is put in use. https://dev.guardianproject.info/issues/1549 --- jni/GNUmakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jni/GNUmakefile b/jni/GNUmakefile index f7787e2..20652fd 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -20,7 +20,8 @@ DEBUG := -g CFLAGS := -Werror -Wall -Wno-deprecated-declarations -Wno-unused-but-set-variable \ -fPIC $(shell gpgme-config --cflags) CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ - -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux + -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \ + -I$(HOME)/code/gnupg/gpgme/src # this is needed for context.h JAVA_BUILD := ../build/classes LDFLAGS := $(shell gpgme-config --thread=pthread --libs) From 2af3b044acdd1d5b2b9720a5e8dae2261600b853 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Mar 2014 10:20:52 -0400 Subject: [PATCH 56/90] remove variable that is never accessed/read and enable that warning --- jni/GNUmakefile | 2 +- jni/GnuPGData.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jni/GNUmakefile b/jni/GNUmakefile index 20652fd..c23d24c 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -17,7 +17,7 @@ CC := gcc INSTALL := install -m 644 DEBUG := -g -CFLAGS := -Werror -Wall -Wno-deprecated-declarations -Wno-unused-but-set-variable \ +CFLAGS := -Werror -Wall -Wno-deprecated-declarations \ -fPIC $(shell gpgme-config --cflags) CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \ diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 0923273..9aabb63 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -170,7 +170,6 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv* env, jobject self, return; } - ssize_t written; while ((nread = (*env)->CallIntMethod(env, in, readMethod, jbuf, (jint)0, BUFSIZE)) != -1) { @@ -179,7 +178,7 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv* env, jobject self, return; } - written = gpgme_data_write(DATA(data), buf, nread); + gpgme_data_write(DATA(data), buf, nread); if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, jbuf); return; From dcf4e8350c6b6bfaf6e7a44114b3c53b138b4d4d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Mar 2014 10:21:34 -0400 Subject: [PATCH 57/90] purge last remnant of old GnuPG 1.4 passphrase handling --- .../freiheit/gnupg/GnuPGPassphraseWindow.java | 96 ------------------- .../freiheit/gnupg/tests/GnuPGTestSuite.java | 11 +-- 2 files changed, 4 insertions(+), 103 deletions(-) delete mode 100644 src/com/freiheit/gnupg/GnuPGPassphraseWindow.java diff --git a/src/com/freiheit/gnupg/GnuPGPassphraseWindow.java b/src/com/freiheit/gnupg/GnuPGPassphraseWindow.java deleted file mode 100644 index 3b52a5a..0000000 --- a/src/com/freiheit/gnupg/GnuPGPassphraseWindow.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * $Id: GnuPGPassphraseWindow.java,v 1.2 2005/01/28 16:05:44 stefan Exp $ - * (c) Copyright 2005 freiheit.com technologies gmbh, Germany. - * - * This file is part of Java for GnuPG (http://www.freiheit.com). - * - * Java for GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * Please see COPYING for the complete licence. - */ -package com.freiheit.gnupg; - -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JPasswordField; - -/** - Requests a passphrase for a crypto operation from the a swing dialog. - This is triggered by gpgme. You must register this as a listener - to the GnuPGContext. It generates a Swing-Dialog. - - @see com.freiheit.gnupg.GnuPGContext - - @author Stefan Richter, stefan@freiheit.com - */ -public class GnuPGPassphraseWindow implements GnuPGPassphraseListener{ - private JFrame _win; - private boolean _internalWin; - - /** - Default-Constructor. - */ - public GnuPGPassphraseWindow(){ - this((JFrame)null); - } - - /** - Use this, if you use this library from a swing application. - @param f where this passphrase dialog should be modal to. - (See Swing-Documentation, if you don't know, what modal dialogs are!) - */ - public GnuPGPassphraseWindow(JFrame f){ - if(f != null){ - _win = f; - _internalWin = false; - } - else{ - _win = new JFrame("GnuPG for Java - freiheit.com technologies gmbh, 2004"); - _internalWin = true; - } - } - - /** - Opens a Swing modal dialog, asks for the passphrase and returns it to gpgme. - */ - public String getPassphrase(String hint, String passphraseInfo, long wasBad){ - JPasswordField passwordField = new JPasswordField(20); - JOptionPane optionPane = new JOptionPane(); - optionPane.setMessage( new Object[] { hint, passwordField } ); - optionPane.setMessageType( JOptionPane.QUESTION_MESSAGE ); - optionPane.setOptionType( JOptionPane.OK_CANCEL_OPTION ); - JDialog dialog = optionPane.createDialog( _win, "Enter GnuPG Passphrase and click OK..." ); - dialog.setVisible(true); - Integer value = (Integer)optionPane.getValue(); - if (value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION ){ - dialog.dispose(); - if(_internalWin){ - _win.dispose(); - } - return null; - } - else{ - StringBuffer buf = new StringBuffer(); - //the newline is REALLY important for gpgme. Don't remove it! - //FIXME: I also add one newline in the native code, but there is still an error condition - buf.append(passwordField.getPassword()).append("\n"); - String passphrase = buf.toString(); - dialog.dispose(); - if(_internalWin){ - _win.dispose(); - } - return passphrase; - } - } -} -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ diff --git a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java index 583dc25..b2e9b0d 100644 --- a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java +++ b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java @@ -13,14 +13,16 @@ */ package com.freiheit.gnupg.tests; -import java.io.File; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; -import com.freiheit.gnupg.*; +import com.freiheit.gnupg.GnuPGContext; +import com.freiheit.gnupg.GnuPGData; +import com.freiheit.gnupg.GnuPGKey; +import com.freiheit.gnupg.GnuPGSignature; /** I will improve this TestSuite later, that everybody can run it without @@ -131,7 +133,6 @@ public void testKeySearch(){ public void testEncryptForOneRecipient(){ GnuPGContext ctx = new GnuPGContext(); - ctx.setPassphraseListener(new GnuPGPassphraseWindow()); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); @@ -145,7 +146,6 @@ public void testEncryptForOneRecipient(){ public void testEncryptForTwoRecipients(){ GnuPGContext ctx = new GnuPGContext(); - ctx.setPassphraseListener(new GnuPGPassphraseWindow()); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); @@ -160,7 +160,6 @@ public void testEncryptForTwoRecipients(){ public void testDecryptFromOneRecipient(){ GnuPGContext ctx = new GnuPGContext(); - ctx.setPassphraseListener(new GnuPGPassphraseWindow()); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); GnuPGData decrypted = ctx.createDataObject(); @@ -187,7 +186,6 @@ public void testAddAndClearSigners(){ public void testSign(){ GnuPGContext ctx = new GnuPGContext(); - ctx.setPassphraseListener(new GnuPGPassphraseWindow()); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData signature = ctx.createDataObject(); @@ -203,7 +201,6 @@ public void testSign(){ public void testEncrypt() { GnuPGContext ctx = new GnuPGContext(); - ctx.setPassphraseListener(new GnuPGPassphraseConsole()); String plaintext = "HALLLLLLLLLLO"; System.out.println( "plaintext: " + plaintext ); From 7e0a74c1381ca421e662cb47f2ed1955fe8bc2db Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Mar 2014 10:25:54 -0400 Subject: [PATCH 58/90] run Eclipse Android-mode code formatter GnuPGTestSuite.java --- .../freiheit/gnupg/tests/GnuPGTestSuite.java | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java index b2e9b0d..75492d4 100644 --- a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java +++ b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java @@ -11,6 +11,7 @@ * * Please see COPYING for the complete licence. */ + package com.freiheit.gnupg.tests; import java.util.Iterator; @@ -25,113 +26,112 @@ import com.freiheit.gnupg.GnuPGSignature; /** - I will improve this TestSuite later, that everybody can run it without - specific fingerprints. It should behave like the tests in gpgme. -

- But the tests can also be seen as code examples. - - @author Stefan Richter, stefan@freiheit.com + * I will improve this TestSuite later, that everybody can run it without + * specific fingerprints. It should behave like the tests in gpgme. + *

+ * But the tests can also be seen as code examples. + * + * @author Stefan Richter, stefan@freiheit.com */ -public class GnuPGTestSuite extends TestCase{ +public class GnuPGTestSuite extends TestCase { private static String HOME = "/tmp/gnupg-for-java-tests"; private static String PLAINTEXT = "I am a not so secret text."; - //Currently, you can not run these test without these fingerprints. - //And: You need to know the passphrases...forget it. + // Currently, you can not run these test without these fingerprints. + // And: You need to know the passphrases...forget it. // but you could add your own fingerprints... private static String CD_FPR = "1C12878CFAA2ECDC81DC43DB12262834A6123FF6"; - //private static String SR_FPR = "F05F385DFA40962D0075AB9C2B80170D"; + // private static String SR_FPR = "F05F385DFA40962D0075AB9C2B80170D"; private static String SR_FPR = "BE54B261FDDF09025D249CAF948C94764B9A38DB"; - //private static GnuPGKey person1 = null; - //private static GnuPGKey person2 = null; - + // private static GnuPGKey person1 = null; + // private static GnuPGKey person2 = null; public static Test suite() { System.out.println("suite()"); - TestSuite suite= new TestSuite(GnuPGTestSuite.class); + TestSuite suite = new TestSuite(GnuPGTestSuite.class); GnuPGContext ctx = getContext(); - String person1Key = " \n"+ - "Key-Type: DSA\n"+ - "Key-Length: 1024\n"+ - "Subkey-Type: ELG-E\n"+ - "Subkey-Length: 1024\n"+ - "Name-Real: alpha\n"+ - "Name-Comment: just a test\n"+ - "Name-Email: alpha@alpha.org\n"+ - "Expire-Date: 0\n"+ - "Passphrase: alpha\n"+ - ""; - ctx.genKey(person1Key,null,null); - //String fpr1 = ctx.getGenkeyResult().getFpr(); - - String person2Key = " \n"+ - "Key-Type: DSA\n"+ - "Key-Length: 1024\n"+ - "Subkey-Type: ELG-E\n"+ - "Subkey-Length: 1024\n"+ - "Name-Real: beta\n"+ - "Name-Comment: just a test\n"+ - "Name-Email: beta@beta.org\n"+ - "Expire-Date: 0\n"+ - "Passphrase: beta\n"+ - ""; - ctx.genKey(person2Key,null,null); - //String fpr2 = ctx.getGenkeyResult().getFpr(); + String person1Key = " \n" + + "Key-Type: DSA\n" + + "Key-Length: 1024\n" + + "Subkey-Type: ELG-E\n" + + "Subkey-Length: 1024\n" + + "Name-Real: alpha\n" + + "Name-Comment: just a test\n" + + "Name-Email: alpha@alpha.org\n" + + "Expire-Date: 0\n" + + "Passphrase: alpha\n" + + ""; + ctx.genKey(person1Key, null, null); + // String fpr1 = ctx.getGenkeyResult().getFpr(); + + String person2Key = " \n" + + "Key-Type: DSA\n" + + "Key-Length: 1024\n" + + "Subkey-Type: ELG-E\n" + + "Subkey-Length: 1024\n" + + "Name-Real: beta\n" + + "Name-Comment: just a test\n" + + "Name-Email: beta@beta.org\n" + + "Expire-Date: 0\n" + + "Passphrase: beta\n" + + ""; + ctx.genKey(person2Key, null, null); + // String fpr2 = ctx.getGenkeyResult().getFpr(); System.out.println("done suite()"); return suite; } - public static GnuPGContext getContext(){ + public static GnuPGContext getContext() { GnuPGContext ctx = new GnuPGContext(); - ctx.setEngineInfo(ctx.getProtocol(),ctx.getFilename(),HOME); + ctx.setEngineInfo(ctx.getProtocol(), ctx.getFilename(), HOME); return ctx; } - public void testEngine(){ + public void testEngine() { GnuPGContext ctx = new GnuPGContext(); ctx.getVersion(); ctx.getFilename(); ctx.getRequiredVersion(); } - public void testContextSetterAndGetter(){ + public void testContextSetterAndGetter() { GnuPGContext ctx = new GnuPGContext(); // Test set/isArmor() - assertTrue(ctx.isArmor());//default: true + assertTrue(ctx.isArmor());// default: true ctx.setArmor(false); assertFalse(ctx.isArmor()); ctx.setArmor(true); assertTrue(ctx.isArmor()); // Test set/isTextmode() - assertTrue(ctx.isTextmode());//default: true + assertTrue(ctx.isTextmode());// default: true ctx.setTextmode(false); assertFalse(ctx.isTextmode()); ctx.setTextmode(true); assertTrue(ctx.isTextmode()); } - public void testKeySearch(){ + public void testKeySearch() { GnuPGContext ctx = new GnuPGContext(); GnuPGKey[] keys = ctx.searchKeys("stefan"); assertNotNull(keys); - for(int i=0; keys != null && i < keys.length; i++){ + for (int i = 0; keys != null && i < keys.length; i++) { assertNotNull(keys[i]); Iterator iter = keys[i].getSignatures(); - System.out.println(keys[i]);//Uncomment to print each key - while(iter.hasNext()){ - assertNotNull((GnuPGSignature)iter.next()); + System.out.println(keys[i]);// Uncomment to print each key + while (iter.hasNext()) { + assertNotNull((GnuPGSignature) iter.next()); } } } - public void testEncryptForOneRecipient(){ + public void testEncryptForOneRecipient() { GnuPGContext ctx = new GnuPGContext(); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); @@ -144,7 +144,7 @@ public void testEncryptForOneRecipient(){ assertNotNull(cipher.toString()); } - public void testEncryptForTwoRecipients(){ + public void testEncryptForTwoRecipients() { GnuPGContext ctx = new GnuPGContext(); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); @@ -158,7 +158,7 @@ public void testEncryptForTwoRecipients(){ assertNotNull(cipher.toString()); } - public void testDecryptFromOneRecipient(){ + public void testDecryptFromOneRecipient() { GnuPGContext ctx = new GnuPGContext(); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData cipher = ctx.createDataObject(); @@ -174,7 +174,7 @@ public void testDecryptFromOneRecipient(){ assertEquals(decrypted.toString(), PLAINTEXT); } - public void testAddAndClearSigners(){ + public void testAddAndClearSigners() { GnuPGContext ctx = new GnuPGContext(); GnuPGKey signer1 = ctx.getKeyByFingerprint(SR_FPR); GnuPGKey signer2 = ctx.getKeyByFingerprint(CD_FPR); @@ -184,7 +184,7 @@ public void testAddAndClearSigners(){ ctx.clearSigners(); } - public void testSign(){ + public void testSign() { GnuPGContext ctx = new GnuPGContext(); GnuPGData plain = ctx.createDataObject(PLAINTEXT); GnuPGData signature = ctx.createDataObject(); @@ -203,9 +203,9 @@ public void testEncrypt() { GnuPGContext ctx = new GnuPGContext(); String plaintext = "HALLLLLLLLLLO"; - System.out.println( "plaintext: " + plaintext ); + System.out.println("plaintext: " + plaintext); GnuPGData plain = ctx.createDataObject(plaintext); - System.out.println( "plain (from data object): \"" + plain.toString() + "\""); + System.out.println("plain (from data object): \"" + plain.toString() + "\""); GnuPGData encrypted = ctx.createDataObject(); GnuPGKey[] recipients = ctx.generateEmptyKeyArray(1); @@ -213,11 +213,11 @@ public void testEncrypt() { ctx.encrypt(recipients, plain, encrypted); - System.out.println("encrypted (from data object: \"" + encrypted.toString() + "\""); + System.out.println("encrypted (from data object: \"" + encrypted.toString() + "\""); String encStr = encrypted.toString(); - assertNotNull( encStr ); + assertNotNull(encStr); assertFalse("Encrypted message cannot be empty.", encStr.length() == 0); } From 7a00a5c81bb6cfc9a45ab58feb4330ca2081181b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Mar 2014 10:41:48 -0400 Subject: [PATCH 59/90] updated README --- README.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 43f89ec..7258dca 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,23 @@ -About GnuPG for Java -======================= +GnuPG for Java +============== -This is a lib I wrote a couple of years ago. It is a native binding to the -gpgme library from Werner Koch. It uses JNI. +GnuPG for Java is a Java wrapper for the gpgme (GnuPG Made Easy) library for +working with the GnuPG encryption suite. It is a native binding to the gpgme +using JNI. It requires gpgme 1.4.3 or newer, and expects to work with GnuPG +2.x as the "engine" in gpgme. With GnuPG 2.x, gpg-agent will handle prompting +the user for the passphrase, as well as passphrase caching. gpgpme is the standard library for developing third-party apps on top of GnuPG. -I wrote it for 32-Bit Intel GNU/Linux platforms. Some of my colleagues added -64-Bit Intel GNU/Linux support. It should run on other Unix-platforms, too. But -this is not tested. Also I am not aware if it runs with the current version -of gpgme. It should be easy to add Windows support by compiling a DLL, adding -this to the jar and extend the loading mechanism to load a DLL on a Windows platform +Stefan Richter originally wrote it for 32-Bit Intel GNU/Linux platforms. Some +of his colleagues added 64-Bit Intel GNU/Linux support. It should build and +run on other UNIX platforms too, but that has not been tested. The Guardian +Project then ported it to GnuPG 2.x and Android as the basis of Gnu Privacy +Guard for Android, and added lots of features and fixed lots of bugs in the +process. + +It should be easy to add Windows support by compiling a DLL, adding this to +the jar and extend the loading mechanism to load a DLL on a Windows platform instead of loading a .so lib. From b0b117744bc8947036356e40c772d94442c08415 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Mar 2014 19:16:14 -0400 Subject: [PATCH 60/90] run gpgme_check_version() in JNI_OnLoad to init thread support "The function gpgme_check_version must be called before any other function in the library, because it initializes the thread support subsystem in GPGME. To achieve this in multi-threaded programs, you must synchronize the memory with respect to other threads that also want to use GPGME. For this, it is sufficient to call gpgme_check_version before creating the other threads using GPGME" https://www.gnupg.org/documentation/manuals/gpgme/Multi-Threading.html --- jni/GnuPGContext.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index cf92ed4..665c342 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -20,6 +20,10 @@ JNI_OnLoad(JavaVM* vm, void* reserved) { _jvm = vm; + // this is required to setup gpgme properly, otherwise it crashes + // https://www.gnupg.org/documentation/manuals/gpgme/Multi-Threading.html + gpgme_check_version(NULL); + // TODO set locale from the JavaVM's config setlocale(LC_ALL, ""); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); From a4d551810bbca145adee08f0025c4e7c8a3eeb79 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 15 Mar 2014 22:49:11 -0400 Subject: [PATCH 61/90] fix javadoc build to make plain javadoc style --- build.xml | 3 +-- etc/stylesheet.css | 41 ----------------------------------------- etc/whitepaper.gif | Bin 11024 -> 0 bytes 3 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 etc/stylesheet.css delete mode 100644 etc/whitepaper.gif diff --git a/build.xml b/build.xml index 47d9b08..ab44217 100644 --- a/build.xml +++ b/build.xml @@ -85,14 +85,13 @@ - diff --git a/etc/guardianproject-logo.png b/etc/guardianproject-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4a2936bb4447ee01318c911ea79cbdbee30707e9 GIT binary patch literal 14589 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 literal 0 HcmV?d00001 From c4a488a4459542c2caa730df94ce3060c941a93b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 11:32:01 -0400 Subject: [PATCH 63/90] fix all javadoc warnings and some related improvements --- src/com/freiheit/gnupg/GnuPGContext.java | 41 +++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index bee5207..c9e3c51 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -195,12 +195,14 @@ public GnuPGKey getSecretKeyByFingerprint(String fingerprint) } /** - * Factory method to generate a GnuPGData-Object from a File. + * Factory method to generate a GnuPGData instance from a File. * - * @param data should not be null be readable - * @return GnuPGData null is data is null or empty, otherwise a - * GnuPGData-Object + * @param f should not be null or a directory and must be readable + * @return GnuPGData instance with data from f, unless + * f is has no readable data in it, then it returns + * null * @throws IOException + * @see com.freiheit.gnupg.GnuPGData */ public GnuPGData createDataObject(File f) throws GnuPGException, IOException { if (f != null && f.exists() && !f.isDirectory() && f.canRead()) { @@ -210,11 +212,13 @@ public GnuPGData createDataObject(File f) throws GnuPGException, IOException { } /** - * Factory method to generate a GnuPGData-Object from a String. + * Factory method to generate a GnuPGData instance from a String. * * @param data should not be null and should have a length > 0 - * @return GnuPGData null is data is null or empty, otherwise a - * GnuPGData-Object + * @return GnuPGData instance based on data, unless + * data is null or has a length of 0, then it returns + * null + * @see com.freiheit.gnupg.GnuPGData */ public GnuPGData createDataObject(String data) throws GnuPGException { if (data == null || data.length() < 1) { @@ -226,11 +230,13 @@ public GnuPGData createDataObject(String data) throws GnuPGException { } /** - * Factory method to generate a GnuPGData-Object from a byte array. + * Factory method to generate a GnuPGData instance from a byte array. * * @param data should not be null and should have a length > 0 - * @return GnuPGData null is data is null or empty, otherwise a - * GnuPGData-Object + * @return GnuPGData instance based on data, unless + * data is null or has a length of 0, then it returns + * null + * @see com.freiheit.gnupg.GnuPGData */ public GnuPGData createDataObject(byte[] data) throws GnuPGException { if (data == null || data.length < 1) { @@ -242,11 +248,10 @@ public GnuPGData createDataObject(byte[] data) throws GnuPGException { } /** - * Factory method to generate an empty GnuPGData-Object. + * Factory method to generate an empty GnuPGData instance. * - * @param data should not be null and should have a length > 0 - * @return GnuPGData null is data is null or empty, otherwise a - * GnuPGData-Object + * @return an empty GnuPGData instance + * @see com.freiheit.gnupg.GnuPGData */ public GnuPGData createDataObject() throws GnuPGException { return new GnuPGData(); @@ -578,8 +583,8 @@ public void decrypt(GnuPGData cipher, GnuPGData plain) throws GnuPGException { * decryption or verification fails, it throws a GnuPGException * . * - * @param cipher holds the data to be decrypted and verified - * @param plain holds the decrypted data after decryption + * @param cipher holds the data to be decrypted and verified + * @param plain holds the decrypted data after decryption * @see com.freiheit.gnupg.GnuPGData */ public void decryptVerify(GnuPGData cipher, GnuPGData plain) throws GnuPGException { @@ -669,8 +674,8 @@ public void clearSigners() throws GnuPGException { /** * Get a specific Signer at a given index. You add Signers with addSigner(). * - * @param int index to the list of Signers - * @return GnuPGKey the key at index, or null if it doesn't exist + * @param index which signer in the list of Signers + * @return the GnuPGKey at index, or null if it doesn't exist * @see com.freiheit.gnupg.GnuPGKey */ public GnuPGKey getSigner(int index) throws GnuPGException { From 727ef483c7a9c3248db554531d360a525052e044 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 15:24:00 -0400 Subject: [PATCH 64/90] generate etags with 'make TAGS' --- .gitignore | 1 + jni/GNUmakefile | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5242b20..485b256 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ dist/ hs_err_pid*.log jni/*.o jni/*.orig +jni/TAGS # generated JNI headers jni/com_freiheit_gnupg_GnuPG*.h lib/libgnupg-for-java.so diff --git a/jni/GNUmakefile b/jni/GNUmakefile index c23d24c..3d36b77 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -55,5 +55,8 @@ test: echo "JNI_HEADERS: $(JNI_HEADERS)" echo "SOURCES: $(SOURCES)" +TAGS: + etags *.c *.h + .PHONY: lib header mids clean test From a74d932c9516d5e410bd633bdba028c335b2b26f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 15:26:10 -0400 Subject: [PATCH 65/90] replace hack using private header with public gpgme_signers_count() This is how I originally figured out how to get it working, then Werner added the gpgme_signers_count() function as of gpgme 1.4.3. fixes #1549 https://dev.guardianproject.info/issues/1549 --- jni/GnuPGContext.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 665c342..1f07f0d 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -7,8 +7,6 @@ #include #include #include -#include - #include "gpgmeutils.h" @@ -486,7 +484,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeGetSignersLength(JNIEnv* env, jobject self, jlong context) { - return (CONTEXT(context)->signers_len); + return (gpgme_signers_count(CONTEXT(context))); } void check_result(gpgme_import_result_t result, char* fpr, int secret) From 1aa53686d9cfe89f45b343957416ab732b682382 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 15:27:42 -0400 Subject: [PATCH 66/90] include data.h from gpgme 1.4.3 Currently, this needs stuff in the private gpgme header data.h, so we include it here for now. Ultimately this should be replaced by code that only uses the public API in gpgme.h --- jni/GNUmakefile | 3 +- jni/GnuPGData.c | 1 + jni/data.h | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 jni/data.h diff --git a/jni/GNUmakefile b/jni/GNUmakefile index 3d36b77..98710f7 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -20,8 +20,7 @@ DEBUG := -g CFLAGS := -Werror -Wall -Wno-deprecated-declarations \ -fPIC $(shell gpgme-config --cflags) CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ - -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \ - -I$(HOME)/code/gnupg/gpgme/src # this is needed for context.h + -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I. JAVA_BUILD := ../build/classes LDFLAGS := $(shell gpgme-config --thread=pthread --libs) diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 9aabb63..52ef8fb 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -5,6 +5,7 @@ #include "gpgmeutils.h" #include +// TODO, this is a private header, figure out public techniques... #include #define BUFSIZE 1024 diff --git a/jni/data.h b/jni/data.h new file mode 100644 index 0000000..3d404af --- /dev/null +++ b/jni/data.h @@ -0,0 +1,137 @@ +/* data.h - Internal data object abstraction interface. + Copyright (C) 2002, 2004, 2005 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef DATA_H +#define DATA_H + +#if HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include + +#include "gpgme.h" + + +/* Read up to SIZE bytes into buffer BUFFER from the data object with + the handle DH. Return the number of characters read, 0 on EOF and + -1 on error. If an error occurs, errno is set. */ +typedef gpgme_ssize_t (*gpgme_data_read_cb) (gpgme_data_t dh, + void *buffer, + size_t size); + +/* Write up to SIZE bytes from buffer BUFFER to the data object with + the handle DH. Return the number of characters written, or -1 on + error. If an error occurs, errno is set. */ +typedef gpgme_ssize_t (*gpgme_data_write_cb) (gpgme_data_t dh, + const void *buffer, + size_t size); + +/* Set the current position from where the next read or write starts + in the data object with the handle DH to OFFSET, relativ to + WHENCE. */ +typedef gpgme_off_t (*gpgme_data_seek_cb) (gpgme_data_t dh, + gpgme_off_t offset, + int whence); + +/* Release the data object with the handle DH. */ +typedef void (*gpgme_data_release_cb) (gpgme_data_t dh); + +/* Get the FD associated with the handle DH, or -1. */ +typedef int (*gpgme_data_get_fd_cb) (gpgme_data_t dh); + +struct _gpgme_data_cbs +{ + gpgme_data_read_cb read; + gpgme_data_write_cb write; + gpgme_data_seek_cb seek; + gpgme_data_release_cb release; + gpgme_data_get_fd_cb get_fd; +}; + +struct gpgme_data +{ + struct _gpgme_data_cbs *cbs; + gpgme_data_encoding_t encoding; + +#ifdef PIPE_BUF +#define BUFFER_SIZE PIPE_BUF +#else +#ifdef _POSIX_PIPE_BUF +#define BUFFER_SIZE _POSIX_PIPE_BUF +#else +#define BUFFER_SIZE 512 +#endif +#endif + char pending[BUFFER_SIZE]; + int pending_len; + + /* File name of the data object. */ + char *file_name; + + union + { + /* For gpgme_data_new_from_fd. */ + int fd; + + /* For gpgme_data_new_from_stream. */ + FILE *stream; + + /* For gpgme_data_new_from_cbs. */ + struct + { + gpgme_data_cbs_t cbs; + void *handle; + } user; + + /* For gpgme_data_new_from_mem. */ + struct + { + char *buffer; + const char *orig_buffer; + /* Allocated size of BUFFER. */ + size_t size; + size_t length; + gpgme_off_t offset; + } mem; + + /* For gpgme_data_new_from_read_cb. */ + struct + { + int (*cb) (void *, char *, size_t, size_t *); + void *handle; + } old_user; + } data; +}; + + +gpgme_error_t _gpgme_data_new (gpgme_data_t *r_dh, + struct _gpgme_data_cbs *cbs); + +void _gpgme_data_release (gpgme_data_t dh); + +/* Get the file descriptor associated with DH, if possible. Otherwise + return -1. */ +int _gpgme_data_get_fd (gpgme_data_t dh); + +#endif /* DATA_H */ From 7524483a508eaafcddd7421a06984f97f040c9b8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 15:54:11 -0400 Subject: [PATCH 67/90] update build version to 0.2-pre --- build.properties | 4 ++-- runTests.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.properties b/build.properties index e8a5dff..ed3289b 100644 --- a/build.properties +++ b/build.properties @@ -1,10 +1,10 @@ # default build.properties app.name=gnupg-for-java -app.version=0.1.6 +app.version=0.2-pre app.customer=LGPL app.vendor=freiheit.com technologies gmbh -app.year=2012 +app.year=2014 build.compiler=modern compile.debug=true diff --git a/runTests.sh b/runTests.sh index a4d8b91..c5df43d 100755 --- a/runTests.sh +++ b/runTests.sh @@ -1,4 +1,4 @@ #STYLE=textui STYLE=swingui #STYLE=awtui -java -Djava.library.path=`pwd`/jni:`pwd`/lib -cp build/jar/gnupg-for-java-0.1.6.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.tests.GnuPGTestSuite +java -Djava.library.path=`pwd`/jni:`pwd`/lib -cp build/jar/gnupg-for-java-0.2-pre.jar:lib/junit-3.8.1.jar junit.${STYLE}.TestRunner com.freiheit.gnupg.tests.GnuPGTestSuite From 9a9ae7af781b23fbfdd610975da3b717165c0f6b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 16:22:58 -0400 Subject: [PATCH 68/90] make JNI headers are optional The headers are only useful during the implementation process, and are not needed during the build process. So make them a separate, optional step. --- jni/GNUmakefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jni/GNUmakefile b/jni/GNUmakefile index 98710f7..fb8211d 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -28,14 +28,14 @@ LDFLAGS := $(shell gpgme-config --thread=pthread --libs) $(GNUPG_LIB): $(OBJECTS) $(CC) $(DEBUG) -shared $(CFLAGS) $^ -o $@ $(LDFLAGS) -$(OBJECTS): $(SOURCES) $(JNI_HEADERS) gpgmeutils.h +$(OBJECTS): $(SOURCES) gpgmeutils.h %.o: %.c $(CC) $(DEBUG) $(CFLAGS) $(CPPFLAGS) -c $< lib: $(GNUPG_LIB) -header: $(JNI_HEADERS) +headers: $(JNI_HEADERS) $(JNI_HEADERS): $(JAVAH) -classpath $(JAVA_BUILD) -jni $(JNI_CLASSES) @@ -46,6 +46,7 @@ mids: clean: rm -f $(OBJECTS) *~ rm -f $(GNUPG_LIB) + rm -f $(JNI_HEADERS) test: echo "JAVA_HOME: --$(JAVA_HOME)--" From c70a921d1e30fde35659efad3028f5c98ed613a0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 17 Mar 2014 16:27:12 -0400 Subject: [PATCH 69/90] quick documentation of build process --- README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7258dca..c76f62e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,24 @@ the jar and extend the loading mechanism to load a DLL on a Windows platform instead of loading a .so lib. +## Building + +To build the gnupg-for-java.jar in build/jar/, run this: + + ant clean jar + +If you want the optional javadoc in build/docs/, run: + + ant javadoc + +For the JNI headers, run: + + make -C jni/ headers + + ## Hacking Notes -Please conform to our code format standard. For C files use format-code.sh. +Please conform to our code format standard. For C files use +./format-code.sh. For Java files, use Eclipse with the Android mode from the +Android project. The default Eclipse formatting is usually close enough. From 524512a283a509484c3f7bb44b026d13efe03b3b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 18 Mar 2014 12:07:12 -0400 Subject: [PATCH 70/90] cleaner way include gpgme's data.h locally --- jni/GNUmakefile | 2 +- jni/GnuPGData.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jni/GNUmakefile b/jni/GNUmakefile index fb8211d..7987b7e 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -20,7 +20,7 @@ DEBUG := -g CFLAGS := -Werror -Wall -Wno-deprecated-declarations \ -fPIC $(shell gpgme-config --cflags) CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ - -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I. + -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux JAVA_BUILD := ../build/classes LDFLAGS := $(shell gpgme-config --thread=pthread --libs) diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 52ef8fb..2349fff 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -6,7 +6,7 @@ #include // TODO, this is a private header, figure out public techniques... -#include +#include "data.h" #define BUFSIZE 1024 From 60825631ef2edb64389c2953fcc28c910ea029e7 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 20 Mar 2014 22:08:22 -0400 Subject: [PATCH 71/90] ignore .class files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 485b256..7f8420f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.class build/ dist/ hs_err_pid*.log From 06522d5657a48dfbdbbedd3340031c0f337db43d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 20 Mar 2014 22:08:32 -0400 Subject: [PATCH 72/90] add run script to examples/ --- examples/run.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 examples/run.sh diff --git a/examples/run.sh b/examples/run.sh new file mode 100755 index 0000000..7d67f66 --- /dev/null +++ b/examples/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +projectroot=`pwd`/.. + +if [ ! -e KeySearch.class ]; then + javac -classpath $projectroot/src KeySearch.java +fi + +java -Djava.library.path=$projectroot/lib \ + -classpath ../build/jar/gnupg-for-java-0.2-pre.jar:. \ + KeySearch From b1a18bb149d94da680ac029c7f39fedc2e330268 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 14:41:59 -0400 Subject: [PATCH 73/90] purge unneeded C test code --- c-test-code/oerks.c | 74 --------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 c-test-code/oerks.c diff --git a/c-test-code/oerks.c b/c-test-code/oerks.c deleted file mode 100644 index e5dfd1b..0000000 --- a/c-test-code/oerks.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include - -/* - * Test for the gpgme gen key function. This function seems - * to hang from time to time. - */ - -static int progress_called; - -static void -progress (void *self, const char *what, int type, int current, int total) -{ - if (!strcmp (what, "primegen") && !current && !total - && (type == '.' || type == '+' || type == '!' - || type == '^' || type == '<' || type == '>')) - { - printf ("%c", type); - fflush (stdout); - progress_called = 1; - } - else - { - fprintf (stderr, "unknown progress `%s' %d %d %d\n", what, type, - current, total); - exit (1); - } -} - -int -main (int argc, char *argv[]) -{ - gpgme_ctx_t ctx; - gpgme_error_t err; - char *p = "\n" \ - "Key-Type: DSA\n" \ - "Key-Length: 1024\n" \ - "Subkey-Type: ELG-E\n" \ - "Subkey-Length: 1024\n" \ - "Name-Real: alpha\n" \ - "Name-Comment: just a test\n" \ - "Name-Email: alpha@alpha.org\n" \ - "Expire-Date: 0\n" \ - "Passphrase: alpha\n" \ - ""; - char *home = "/tmp/gnupg"; - - if (argc > 1) - { - home = argv[1]; - } - - err = gpgme_new (&ctx); - //fprintf(stderr, "gpgme_new, result: %d\n", err); - //gpgme_set_armor (ctx, 1); - //fprintf(stderr, "gpgme_set_armor, result: %d\n", err); - //gpgme_set_textmode (ctx, 1); - //fprintf(stderr, "gpgme_set_textmode, result: %d\n", err); - //err = gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS); - //fprintf(stderr, "gpgme_set_keylist_mode, result: %d\n", err); - fprintf (stderr, "set home to \"%s\"\n", home); - err = gpgme_ctx_set_engine_info (ctx, 0, "/usr/bin/gpg", home); - fprintf(stderr, "gpgme_set_engine_info, result: %d\n", err); - - fprintf(stderr, "starting genkey: \"%s\"\n", p); - - gpgme_set_progress_cb (ctx, progress, NULL); - err = gpgme_op_genkey(ctx, p, NULL, NULL); - - fprintf(stderr, "done, result: %d\n", err); - - return 0; -} From f15d15c052869ab372d886a8ac6ad389bce05e34 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 14:44:34 -0400 Subject: [PATCH 74/90] include a bunch of relevant files to test with --- tests/android-signing-key.p12 | Bin 0 -> 661 bytes tests/icon-encrypted-not-signed.png.gpg | Bin 0 -> 9709 bytes tests/icon.png | Bin 0 -> 9413 bytes tests/icon.png.asc | 214 ++++++++++++++++++++++++ tests/icon.png.gpg | Bin 0 -> 19878 bytes tests/icon.png.sig | Bin 0 -> 543 bytes tests/one-public-key.pkr | Bin 0 -> 102286 bytes tests/public-keys.pkr | Bin 0 -> 152896 bytes tests/public-keys.pkr.asc | 18 ++ tests/public-keys.pkr.sig | Bin 0 -> 543 bytes tests/pubring.gpg | Bin 0 -> 1179 bytes tests/secret | 1 + tests/secret-keys.skr | Bin 0 -> 2549 bytes tests/secret.gpg | Bin 0 -> 367 bytes tests/secring.gpg | Bin 0 -> 2557 bytes tests/trustdb.gpg | Bin 0 -> 1280 bytes 16 files changed, 233 insertions(+) create mode 100644 tests/android-signing-key.p12 create mode 100644 tests/icon-encrypted-not-signed.png.gpg create mode 100644 tests/icon.png create mode 100644 tests/icon.png.asc create mode 100644 tests/icon.png.gpg create mode 100644 tests/icon.png.sig create mode 100644 tests/one-public-key.pkr create mode 100644 tests/public-keys.pkr create mode 100644 tests/public-keys.pkr.asc create mode 100644 tests/public-keys.pkr.sig create mode 100644 tests/pubring.gpg create mode 100644 tests/secret create mode 100644 tests/secret-keys.skr create mode 100644 tests/secret.gpg create mode 100644 tests/secring.gpg create mode 100644 tests/trustdb.gpg diff --git a/tests/android-signing-key.p12 b/tests/android-signing-key.p12 new file mode 100644 index 0000000000000000000000000000000000000000..0a9bec81a6ff14e52a856c9a0d519a705ac69c51 GIT binary patch literal 661 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 literal 0 HcmV?d00001 diff --git a/tests/icon.png b/tests/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5c58dc7df68fe43e436e3501566023cabc7ff656 GIT binary patch literal 9413 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 P4FF(C1&InV1ONX4NTqFO literal 0 HcmV?d00001 diff --git a/tests/icon.png.asc b/tests/icon.png.asc new file mode 100644 index 0000000..070c840 --- /dev/null +++ b/tests/icon.png.asc @@ -0,0 +1,214 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.11 (GNU/Linux) +Comment: GPGTools - http://gpgtools.org + +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 +IKzU4PSn8n8A +=jw1k +-----END PGP MESSAGE----- diff --git a/tests/icon.png.gpg b/tests/icon.png.gpg new file mode 100644 index 0000000000000000000000000000000000000000..7d38bdc0b1ddc3791005b3e7f44f1fbfc4280323 GIT binary patch literal 19878 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%0DSF*ro*-}Y>tY$xZ*rH=njh$Pk-HsFMeDJFjKca z!z0~KIs1Pj?~)qkrxl>-_fM-_YvVHm*6TP9x^Djq4s}4!@~j>@}p5OF%8E`)Q$E?H~m@)ZU}@Cx?SOuNE;m^Q&ZaccA6^w6N0W z^7iFg?HJitq6ox;n;{&iDMWhGAzAjWW{Tewgf=58{vGb!Ff)Q}w`6an7h62!d$e6+ zkfMn*E(V@W0uVdd&HToLHYfsUYY``TvNM19A+rh-w6iI>q7*qu>z1HyI>>SBIJ&O~ zbNEA}4>TW-d7eu&Gw&EN1eLx0*L91yp_3)B`S)d-1EA{PuQ0s0zd~gJUhzraumKGz zlUJ@HZ2hS>2EPI;@qFuYpYYO~iXQmsu7s@BrQ7Ir?f=Hc#9!DO2*=q@AkC#!4D08<-*TJkO6}iKc}-|YceqUHd(YV`hLx^-E0RG znzo;3Gz=z-h6ND@YB=qIy%A~k*^<1l-JhtlcWUe$`lLGGMSnE;4;aI!%#A9a@o(Ke zm#Q^|0v9I{PK80c4j=2;LD+2;FJ0REe)E!#p@sJ17)8>jYX2e4moR~~hu%n-o)}Do zvAV`Eeh=5*(L~Pj>aM4R3_J$@Q+XevXcdqltX`TVh%LhrC*IFhU1DlrCexm)n)aqM z`2N6ZN#+oLOZsl#Y|qK9s#QA@jo~&nJZJ+5eh3$pz_=OS~2F{PAr-nC~j0+exOY z9Jn+xeAuu}xQEE_6HO$0JG8*VwSgvlNtV7$=slLtyezw1dQt#X8p5j0TQ&yqVuz=M z+_6Kh+W`Kh{_%RPJ={>$DJ`9!xbPUxB&$$eiuy$GeHG3rO z?XInfw^@4oqGfIWWZc({ov#fvNBVQW=uM-`y~E@Jk7KV`Eq^b-^%amWvkF+8&VsIg&Mf@A!iChPpb<2as6&X48XR|61db*r(L$ z&I(hE6@B=CyeB9=vR#cP-utMJ!2iHI8hsJH=Gd8TPTRphF4N^niL=%<3w&}h^8YzG zN#kfCmj1GkC%bE|d!i0;{Lus22Sy%#3W01>-v)g(4p8F^Bz<8}PC%ANSxH3YFYvgc z^wR+L!GxQL?gwrxfz6}|>9vh|+ix~|?~Jq={vTcbxU=MSUVq9|Mbs0>UaM!AroIG! zTxtx&*n+9PFT;&Vg;L?X6|zj;)gR!&7K&1JV$Z6)7pX&j@Gle$?y}qGZ@QCdR`SeH zFhmfaxj{!+{kf0H21tg_e0P#zkpw|suY5aGh`jZv^lu6HT|aqn8Ssb+^KS~ud-sCf zzim$!cdIL-GFwWZ#>|Z2HcMoHkAxaPGZ>6kAzC) zY{k!3s5hr&ve**JmldXy_nDf`CdH4*9ule&8|HsC>Vr7kctPr2u=%RB{>yOp3%$-F0nqmTSWwi&Pz^` ztPGCclX!_wz5%(!!-N2*GmuL8srFubJ|>m3Ko26{u)S-s0U5`9W=mP7c$Ayg?~j6L zdtex-qs;f;v})+*%L)EVood~Xyj}^6a|^LPC?EjD@}XpogqCTTGy$sM#R9k^K@_zS zR~ZKk95F$ux8@q+sA8!9G8z!3zCZM8^<>M@&5N5uW;y@^B#KkQ$%k?kk-HeHVco_ zP*;g5Vg>?NdRt})#6GCP9+eJ~2M)ThJ!8n94*f|qKqjFwbM$KUBdM9WN|LH$a{C`q zSj!af)()ZJLn43W8#zX}2%afSQ%wFTF473+0#! z#C(~t-PzEWb|g@e^hqd*kE$rKX?0>X$6x?#?3!Nom$yPgkq}*_4o<04xceD~>JN9r zFD@&O7!#>I+6B>b(-Dk+BJ|r2#0)RZ654;N)@%>m6iEeKV*1z=eeg8b{ux6c;yv4i zC!f1xQ*^0=fmg8XWiQa0LZ)}?t6=Pc`&o#Wx>VD(&?ll|DmNH1z-c1Q=)pU^T(;Lq d(+h*UH+TDAaJNdtem(Ls#zcf-Mo#?dyyHscbP)gm literal 0 HcmV?d00001 diff --git a/tests/icon.png.sig b/tests/icon.png.sig new file mode 100644 index 0000000000000000000000000000000000000000..97ef5c67e50c4ad21ec2b63ecbb7c0b9d45fb328 GIT binary patch literal 543 zcmV+)0^t3L0vrSY0SEvF1p-muiz)yL2@szT<%c&*zJbp15C45gF&fqsv%>B?o!5WY z{E17+Y(E}>8U+{FhVe)YRH!@RqVR~6o*G)9Lyv>}#jUW>1w>|)4j#l~&1Mpx5kWil z56aFJVp)N?t1K8n1hI?s9o8p+Shy|wIC5o6ki};*zj5B8njlbGm{{a|`(Bm>X!t&% z^s?S0J^K`1fgO&5-o}rY)QNMrg0vRhLr6Nh{eSS@?Wk_B=zATdZ`y-z-gKI~bMVSW zT4ION+xf%8e1qCgoo`E);=RQD8F+7JZ1u7O2)*g$cB$ zB3(9dlA{Mgik7n}s+|fqQf3~Rgb6*izR$y*!_6oQ< hs#1awja+qR7^+t%H^|1<8{=XE{I9686A8IcjO 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 z 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

  • 7!n87&3UQSG)u+9vCY!X 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 literal 0 HcmV?d00001 diff --git a/tests/pubring.gpg b/tests/pubring.gpg new file mode 100644 index 0000000000000000000000000000000000000000..5882e73c7b31d467a91a24d460ef9541a3e6a16e GIT binary patch literal 1179 zcmV;M1Z4Y}0SyFD-yNI*2ms7;c{`na{R`p@ReN424(NKOn8tu)TE`fC1HYz%x&sx{ zFjJ<=4@rUiEOZc70Z8-y#%TVgBCaLbiV@Ma-li@ny<{EZ5?eLLbc@8#KTW`^^H9p) zq;uiR>L;je!n&-afFlAoS_3R~!~^%W!sq!tI+k%%^&-)7Qv^~Z*i}L>p=9l%(gr8t zG;}nUmw$I`YXylvE=l9j&h`PK&I*HudB)MR(PgtzM=ef0wAyX66pyUyKm8aM+>fkz z?PE5EF8APLi*YQVe|}UnGu=u8eZ)Lbh+d?d5e$2}%@f2$Gw9ARY7(fyJMN~A!g%2> zM}u>X`+34#AWh(9*Np%X0RREC6jWt%bRbJ*c_1ioX>K|oF)}kWDTx6%1QP)Q03rnf zP~RP#0viJc3ke7Z0|EvW2m%QT3j`Jd0|5da0Rk6*0162Z96J1PQSX{4dvpi@xezk? zxZ(-#Q_&ZH;v>@XTN9QO;V)ZvXDePiF1U_jDINe#|Ko2b-(jY3p_+^n5Idk`CCtK$ zr9sdZQP zK3~=M?#``)_N&6P2D1L)1LEm**+iPLdDL4Gr)M8!&XXPuBgbBeW?JT=^+XLe)flNh zXUik3AN?$Rf~f99#vPAB3g<{sCY(;I0)aODSkjgE`ld`s+O{9Di=SFvajc# zJX*Nmni2csWGzz3Daz^3wIupkawDGqC?l_VmN5J)AcGR0;E&qI=m=I^B1QwEt2y4& zF%9x>*tadc{3xJws?_%7;EE)0JN_sf2snrwQvLq}NDQ>5mPgc%h-f4}d2l3X$v(u$4 zX=NJ#5di=Ji2)x37y$wR2?YXB-yNI+8w>yn2@o7Q{BTk4nkXe-2mrALz%KWPc4$oM z8#BsVmWR}zQ8l01sVJtmQn$UoDp~Qo*rui@bGCuJ7ow}@)`Q}7T`2R1=Y`a<+UIot zlf#JaKI`myGSaifazPk}KgB2nEE2QT6eN5B+C)(LL9HmY;Uc}kr???nzZaAHHcs4T z3_$T%{9}KC$M3PT^ANBa7Xlwnf5RcYJV16snw6LO)ySMofMOi7j&ibfD4I1ik9n%B z%LjZ1&$N>Y@Hw%`sjrrMgTj9_0^`)E&vs270y8NDX&KRb6mze(8 taHwSLtt<=kRmc_ZIcd|fPUCQtx(H#Ms?^BMc{x{ApR;pg2l=o900TGmC42w? literal 0 HcmV?d00001 diff --git a/tests/secret b/tests/secret new file mode 100644 index 0000000..a9b5729 --- /dev/null +++ b/tests/secret @@ -0,0 +1 @@ +Attack across river at dawn. diff --git a/tests/secret-keys.skr b/tests/secret-keys.skr new file mode 100644 index 0000000000000000000000000000000000000000..53332d08d833e0c8a8efeedb5ed827c2b5b54b39 GIT binary patch literal 2549 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 LS5=?0b7Kej<%`Eo literal 0 HcmV?d00001 diff --git a/tests/secret.gpg b/tests/secret.gpg new file mode 100644 index 0000000000000000000000000000000000000000..ec5d34956d228f146dad8e5f32cd91058dd4d3a4 GIT binary patch literal 367 zcmV-#0g(QM0Sp5c_-%zVKLJev2me%oeDYW_5N2>=yq}TCiYs*Q@D7~70~MZd3#_3H zDS0^mc0+^&s=rg|nd&iXjhI66+C0D$1jH>@_4u%S|LI{OxIP(!J4v+zgW2#UdUDT+ zJP{3Y#p-x|K|LT_^fD)hWayJKely8RCN7YFc?# z0~x6>UFO_v@ff8E?eOo=;y6C|oX7!KPkW;1-rqlW0DEf_YctQ~g5pLQ8)mBLHxs@0 z$I+c?F8NjqI{U+Qwt~*gSV+=d0UF6a$rw+5;t&o!{SkXg?rz_}fuv6$*?|I@&XWNg zl%RjiX>2(JoBtk=A=f{M?72;j1ElzZh$+9fQo&*>+tVYz@(jwAmBIn}IlX|YvXX$r NV>&zRfGh*UT*&$xuRZ_( literal 0 HcmV?d00001 diff --git a/tests/secring.gpg b/tests/secring.gpg new file mode 100644 index 0000000000000000000000000000000000000000..8e28f09b6c4cb49f0f5963c9f03dfeea6ecc2342 GIT binary patch literal 2557 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 T$jx~ Date: Fri, 21 Mar 2014 16:08:46 -0400 Subject: [PATCH 75/90] move format-code.sh to jni/ since it is only used there --- format-code.sh => jni/format-code.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename format-code.sh => jni/format-code.sh (90%) diff --git a/format-code.sh b/jni/format-code.sh similarity index 90% rename from format-code.sh rename to jni/format-code.sh index f6a53dd..59e3558 100755 --- a/format-code.sh +++ b/jni/format-code.sh @@ -13,6 +13,6 @@ else ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --pad-header --align-pointer=type --align-reference=type" fi -$ASTYLE $ASTYLE_ARGS jni/*.h -$ASTYLE $ASTYLE_ARGS jni/*.c +$ASTYLE $ASTYLE_ARGS *.h +$ASTYLE $ASTYLE_ARGS *.c From 7ac81bb7b18cd57c6051bac58d1de5535848740c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 16:11:05 -0400 Subject: [PATCH 76/90] fix tests in Eclipse: set path to libgnupg-for-java.so --- .classpath | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.classpath b/.classpath index 2d3c2eb..4577e74 100644 --- a/.classpath +++ b/.classpath @@ -2,7 +2,11 @@ - + + + + + From 9e54a1746953db343b56943b8bc71fa677901936 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 16:17:19 -0400 Subject: [PATCH 77/90] update format-code.sh to get closest to current style Running the original script made a lot of changes to the code, the edits to the script caused the least amount of changes for me. --- jni/format-code.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jni/format-code.sh b/jni/format-code.sh index 59e3558..97b787d 100755 --- a/jni/format-code.sh +++ b/jni/format-code.sh @@ -6,12 +6,7 @@ if [[ $? -ne 0 ]]; then exit 1 fi -$ASTYLE --help 2>&1 | grep "pad-first-paren-out" > /dev/null -if [[ $? -eq 0 ]]; then - ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --unpad-paren --pad-first-paren-out --pad-header --align-pointer=type --align-reference=type" -else - ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --pad-header --align-pointer=type --align-reference=type" -fi +ASTYLE_ARGS="--style=kr --indent=spaces=4 --convert-tabs --pad-oper --unpad-paren --pad-header --align-pointer=type --align-reference=type" $ASTYLE $ASTYLE_ARGS *.h $ASTYLE $ASTYLE_ARGS *.c From cf92f88429c2525c70c5e8c68908b7038a282121 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 16:24:26 -0400 Subject: [PATCH 78/90] reformat all .c and .h files with updated format-code.sh --- jni/GnuPGContext.c | 37 ++++++------- jni/GnuPGData.c | 8 +-- jni/GnuPGSignature.c | 8 +-- jni/data.h | 128 +++++++++++++++++++++---------------------- jni/gpgmeutils.h | 4 +- 5 files changed, 89 insertions(+), 96 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 1f07f0d..7db94b8 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -89,7 +89,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncrypt(JNIEnv* env, return; } - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; } @@ -120,7 +120,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecrypt(JNIEnv* env, { gpgme_error_t err; - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; } @@ -242,7 +242,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpEncryptSign(JNIEnv* env, return; } - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; } @@ -272,7 +272,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDecryptVerify(JNIEnv* env, { gpgme_error_t err; - err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(cipher)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; } @@ -382,7 +382,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, //copy string object from java to native string const jsize query_len = (*env)->GetStringLength(env, query); const jbyte* query_str = (jbyte*)(*env)->GetStringUTFChars(env, query, - NULL); + NULL); //get the right constructor to invoke for every key in result set jclass keyClass; keyClass = (*env)->FindClass(env, "com/freiheit/gnupg/GnuPGKey"); @@ -397,8 +397,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, } gpgme_error_t err = gpgme_op_keylist_start(CONTEXT(context), - query_len > 0 ? (const char*)query_str : NULL, - secret_only); + query_len > 0 ? (const char*)query_str : NULL, secret_only); if (UTILS_onErrorThrowException(env, err)) { (*env)->ReleaseStringUTFChars(env, query, (const char*)query_str); return NULL; @@ -408,14 +407,14 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, jlong num_keys_found = 0; struct _keyInList { gpgme_key_t key; - struct _keyInList *next; + struct _keyInList* next; }; - typedef struct _keyInList *keyInList; + typedef struct _keyInList* keyInList; keyInList current, next, head = NULL; while (!err) { err = gpgme_op_keylist_next(CONTEXT(context), &key); if ((gpg_err_code(err) != GPG_ERR_EOF) - && UTILS_onErrorThrowException(env, err)) { + && UTILS_onErrorThrowException(env, err)) { return NULL; } else if (err) { break; // we have nothing, quit before setting the list @@ -429,11 +428,11 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeKeylist(JNIEnv* env, current = head; jobject keyObj = NULL; jobjectArray result = (*env)->NewObjectArray(env, - num_keys_found, - keyClass, - NULL); + num_keys_found, + keyClass, + NULL); int i; - for(i = 0; i < num_keys_found; i++) { + for (i = 0; i < num_keys_found; i++) { key = current->key; keyObj = (*env)->NewObject(env, keyClass, cid, LNG(key)); (*env)->SetObjectArrayElement(env, result, i, keyObj); @@ -623,7 +622,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpImport(JNIEnv* env, gpgme_error_t err; gpgme_import_result_t result; - err = gpgme_data_rewind(DATA(keydata)); //TODO: Use seek instead of rewind + err = gpgme_data_rewind(DATA(keydata)); //TODO: Use seek instead of rewind if (UTILS_onErrorThrowException(env, err)) { return; } @@ -702,7 +701,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpGenKey(JNIEnv* env, char* p; gpgme_error_t err; - p = (char*) (*env)->GetStringUTFChars(env, params, NULL); + p = (char*)(*env)->GetStringUTFChars(env, params, NULL); fprintf(stderr, "genKey: \"%s\"\n", p); @@ -732,7 +731,7 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpExport(JNIEnv* env, gpgme_error_t err; - p = (char*) (*env)->GetStringUTFChars(env, pattern, NULL); + p = (char*)(*env)->GetStringUTFChars(env, pattern, NULL); err = gpgme_op_export(ctx, p, 0, data); if (UTILS_onErrorThrowException(env, err)) { return; @@ -755,8 +754,8 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeCtxSetEngineInfo(JNIEnv* env, char* home_dir; gpgme_error_t err; - file_name = (char*) (*env)->GetStringUTFChars(env, fileName, NULL); - home_dir = (char*) (*env)->GetStringUTFChars(env, homeDir, NULL); + file_name = (char*)(*env)->GetStringUTFChars(env, fileName, NULL); + home_dir = (char*)(*env)->GetStringUTFChars(env, homeDir, NULL); /*fprintf(stderr, "set engine info: proto: %d, fileName: %s, homeDir: %s\n", proto, file_name, home_dir);*/ diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index 2349fff..c7d89da 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -14,7 +14,7 @@ JNIEXPORT jsize JNICALL Java_com_freiheit_gnupg_GnuPGData_gpgmeSize(JNIEnv* env, jobject self, jlong data) { - return (jsize) (DATA(data))->data.mem.size; + return (jsize)(DATA(data))->data.mem.size; } JNIEXPORT jlong JNICALL @@ -40,7 +40,7 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataNewFromMem(JNIEnv* env, return LNG(NULL); } - (*env)->ReleaseByteArrayElements(env, plain, plain_ptr, 0); //RELMEM(0) + (*env)->ReleaseByteArrayElements(env, plain, plain_ptr, 0); //RELMEM(0) jlong result = LNG(data); return result; } @@ -108,7 +108,7 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataWrite(JNIEnv* env, jobject self, jbyteArray jbuf; - err = (gpgme_data_seek ( DATA(data), (off_t)0, SEEK_SET ) < 0); + err = (gpgme_data_seek(DATA(data), (off_t)0, SEEK_SET) < 0); if (UTILS_onErrorThrowException(env, err)) { fprintf(stderr, "error throw exception! abort.\n"); return; @@ -166,7 +166,7 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv* env, jobject self, jbyteArray jbuf = (*env)->NewByteArray(env, BUFSIZE); //GETMEM(0) jlong nread; - err = (gpgme_data_seek (DATA(data), (off_t)0, SEEK_SET) < 0); + err = (gpgme_data_seek(DATA(data), (off_t)0, SEEK_SET) < 0); if (UTILS_onErrorThrowException(env, err)) { return; } diff --git a/jni/GnuPGSignature.c b/jni/GnuPGSignature.c index a3e3c68..fa71bf2 100644 --- a/jni/GnuPGSignature.c +++ b/jni/GnuPGSignature.c @@ -9,21 +9,21 @@ JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetRevoked(JNIEnv* env, jobject self, jlong sig) { - return (jboolean) (KEYSIG(sig))->revoked; + return (jboolean)(KEYSIG(sig))->revoked; } JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExpired(JNIEnv* env, jobject self, jlong sig) { - return (jboolean) (KEYSIG(sig))->expired; + return (jboolean)(KEYSIG(sig))->expired; } JNIEXPORT jboolean JNICALL Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetInvalid(JNIEnv* env, jobject self, jlong sig) { - return (jboolean) (KEYSIG(sig))->invalid; + return (jboolean)(KEYSIG(sig))->invalid; } JNIEXPORT jboolean JNICALL @@ -31,7 +31,7 @@ Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetExportable(JNIEnv* env, jobject self, jlong sig) { - return (jboolean) (KEYSIG(sig))->exportable; + return (jboolean)(KEYSIG(sig))->exportable; } JNIEXPORT jstring JNICALL diff --git a/jni/data.h b/jni/data.h index 3d404af..73dfdb5 100644 --- a/jni/data.h +++ b/jni/data.h @@ -36,43 +36,41 @@ /* Read up to SIZE bytes into buffer BUFFER from the data object with the handle DH. Return the number of characters read, 0 on EOF and -1 on error. If an error occurs, errno is set. */ -typedef gpgme_ssize_t (*gpgme_data_read_cb) (gpgme_data_t dh, - void *buffer, - size_t size); +typedef gpgme_ssize_t (*gpgme_data_read_cb)(gpgme_data_t dh, + void* buffer, + size_t size); /* Write up to SIZE bytes from buffer BUFFER to the data object with the handle DH. Return the number of characters written, or -1 on error. If an error occurs, errno is set. */ -typedef gpgme_ssize_t (*gpgme_data_write_cb) (gpgme_data_t dh, - const void *buffer, - size_t size); +typedef gpgme_ssize_t (*gpgme_data_write_cb)(gpgme_data_t dh, + const void* buffer, + size_t size); /* Set the current position from where the next read or write starts in the data object with the handle DH to OFFSET, relativ to WHENCE. */ -typedef gpgme_off_t (*gpgme_data_seek_cb) (gpgme_data_t dh, - gpgme_off_t offset, - int whence); +typedef gpgme_off_t (*gpgme_data_seek_cb)(gpgme_data_t dh, + gpgme_off_t offset, + int whence); /* Release the data object with the handle DH. */ -typedef void (*gpgme_data_release_cb) (gpgme_data_t dh); +typedef void (*gpgme_data_release_cb)(gpgme_data_t dh); /* Get the FD associated with the handle DH, or -1. */ -typedef int (*gpgme_data_get_fd_cb) (gpgme_data_t dh); - -struct _gpgme_data_cbs -{ - gpgme_data_read_cb read; - gpgme_data_write_cb write; - gpgme_data_seek_cb seek; - gpgme_data_release_cb release; - gpgme_data_get_fd_cb get_fd; +typedef int (*gpgme_data_get_fd_cb)(gpgme_data_t dh); + +struct _gpgme_data_cbs { + gpgme_data_read_cb read; + gpgme_data_write_cb write; + gpgme_data_seek_cb seek; + gpgme_data_release_cb release; + gpgme_data_get_fd_cb get_fd; }; -struct gpgme_data -{ - struct _gpgme_data_cbs *cbs; - gpgme_data_encoding_t encoding; +struct gpgme_data { + struct _gpgme_data_cbs* cbs; + gpgme_data_encoding_t encoding; #ifdef PIPE_BUF #define BUFFER_SIZE PIPE_BUF @@ -83,55 +81,51 @@ struct gpgme_data #define BUFFER_SIZE 512 #endif #endif - char pending[BUFFER_SIZE]; - int pending_len; - - /* File name of the data object. */ - char *file_name; - - union - { - /* For gpgme_data_new_from_fd. */ - int fd; - - /* For gpgme_data_new_from_stream. */ - FILE *stream; - - /* For gpgme_data_new_from_cbs. */ - struct - { - gpgme_data_cbs_t cbs; - void *handle; - } user; - - /* For gpgme_data_new_from_mem. */ - struct - { - char *buffer; - const char *orig_buffer; - /* Allocated size of BUFFER. */ - size_t size; - size_t length; - gpgme_off_t offset; - } mem; - - /* For gpgme_data_new_from_read_cb. */ - struct - { - int (*cb) (void *, char *, size_t, size_t *); - void *handle; - } old_user; - } data; + char pending[BUFFER_SIZE]; + int pending_len; + + /* File name of the data object. */ + char* file_name; + + union { + /* For gpgme_data_new_from_fd. */ + int fd; + + /* For gpgme_data_new_from_stream. */ + FILE* stream; + + /* For gpgme_data_new_from_cbs. */ + struct { + gpgme_data_cbs_t cbs; + void* handle; + } user; + + /* For gpgme_data_new_from_mem. */ + struct { + char* buffer; + const char* orig_buffer; + /* Allocated size of BUFFER. */ + size_t size; + size_t length; + gpgme_off_t offset; + } mem; + + /* For gpgme_data_new_from_read_cb. */ + struct { + int (*cb)(void*, char*, size_t, size_t*); + void* handle; + } old_user; + } data; }; -gpgme_error_t _gpgme_data_new (gpgme_data_t *r_dh, - struct _gpgme_data_cbs *cbs); +gpgme_error_t _gpgme_data_new(gpgme_data_t* r_dh, + struct _gpgme_data_cbs* cbs); -void _gpgme_data_release (gpgme_data_t dh); +void _gpgme_data_release(gpgme_data_t dh); /* Get the file descriptor associated with DH, if possible. Otherwise return -1. */ -int _gpgme_data_get_fd (gpgme_data_t dh); +int _gpgme_data_get_fd(gpgme_data_t dh); -#endif /* DATA_H */ +#endif /* DATA_H */ diff --git a/jni/gpgmeutils.h b/jni/gpgmeutils.h index 25a81ad..d6fb803 100644 --- a/jni/gpgmeutils.h +++ b/jni/gpgmeutils.h @@ -35,12 +35,12 @@ int UTILS_copyRecipientsFromJvm(JNIEnv* env, jlongArray recipients, gpgme_key_t // don't use this directly, it is wrapped by the PTR() macro inline static void* _ptrFromJLong(jlong l) { - return (void*) (unsigned long) l; + return (void*)(unsigned long) l; } // don't use this directly, it is wrapped by the PTR() macro inline static jlong _jlongFromPtr(void* p) { - return (jlong) (unsigned long) p; + return (jlong)(unsigned long) p; } #endif From d4b23c37e412b54e3579df1f173c204382c202a5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 21 Mar 2014 16:39:22 -0400 Subject: [PATCH 79/90] including emacs formatting commands at end of every code file This makes emacs automatically setup the right code formatting when it loads any of these files. --- jni/GnuPGContext.c | 9 +++++++++ jni/GnuPGData.c | 9 +++++++++ jni/GnuPGGenkeyResult.c | 9 +++++++++ jni/GnuPGKey.c | 9 +++++++++ jni/GnuPGSignature.c | 9 +++++++++ jni/data.h | 9 +++++++++ jni/gpgmeutils.c | 9 +++++++++ jni/gpgmeutils.h | 9 +++++++++ src/com/freiheit/gnupg/GnuPGContext.java | 2 ++ src/com/freiheit/gnupg/GnuPGData.java | 2 ++ src/com/freiheit/gnupg/GnuPGException.java | 2 ++ src/com/freiheit/gnupg/GnuPGGenkeyResult.java | 2 ++ src/com/freiheit/gnupg/GnuPGKey.java | 2 ++ src/com/freiheit/gnupg/GnuPGPeer.java | 2 ++ src/com/freiheit/gnupg/GnuPGSignature.java | 2 ++ src/com/freiheit/gnupg/tests/GnuPGTestSuite.java | 9 ++------- 16 files changed, 88 insertions(+), 7 deletions(-) diff --git a/jni/GnuPGContext.c b/jni/GnuPGContext.c index 7db94b8..b3fbe3f 100644 --- a/jni/GnuPGContext.c +++ b/jni/GnuPGContext.c @@ -829,3 +829,12 @@ Java_com_freiheit_gnupg_GnuPGContext_gpgmeOpDelete(JNIEnv* env, return; } } + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/GnuPGData.c b/jni/GnuPGData.c index c7d89da..51890b8 100644 --- a/jni/GnuPGData.c +++ b/jni/GnuPGData.c @@ -189,3 +189,12 @@ Java_com_freiheit_gnupg_GnuPGData_gpgmeDataRead(JNIEnv* env, jobject self, (*env)->DeleteLocalRef(env, jbuf); //RELMEM(0) } + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/GnuPGGenkeyResult.c b/jni/GnuPGGenkeyResult.c index b10c45e..0be2470 100644 --- a/jni/GnuPGGenkeyResult.c +++ b/jni/GnuPGGenkeyResult.c @@ -29,3 +29,12 @@ Java_com_freiheit_gnupg_GnuPGGenkeyResult_gpgmeGetSub(JNIEnv* env, { return (GENKEYRESULT(result))->primary; } + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/GnuPGKey.c b/jni/GnuPGKey.c index 84eb9c4..72c6b8b 100644 --- a/jni/GnuPGKey.c +++ b/jni/GnuPGKey.c @@ -206,3 +206,12 @@ Java_com_freiheit_gnupg_GnuPGKey_gpgmeHasSecretKey(JNIEnv* env, jobject self, /* (*env)->SetObjectField(env, self, fpr_fld, fpr_jstr); */ /* } */ + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/GnuPGSignature.c b/jni/GnuPGSignature.c index fa71bf2..fecd1a3 100644 --- a/jni/GnuPGSignature.c +++ b/jni/GnuPGSignature.c @@ -81,3 +81,12 @@ Java_com_freiheit_gnupg_GnuPGSignature_gpgmeGetNextSignature(JNIEnv* env, { return LNG((KEYSIG(sig))->next); } + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/data.h b/jni/data.h index 73dfdb5..415c7a3 100644 --- a/jni/data.h +++ b/jni/data.h @@ -129,3 +129,12 @@ void _gpgme_data_release(gpgme_data_t dh); int _gpgme_data_get_fd(gpgme_data_t dh); #endif /* DATA_H */ + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/gpgmeutils.c b/jni/gpgmeutils.c index bc7270b..4ee9b5b 100644 --- a/jni/gpgmeutils.c +++ b/jni/gpgmeutils.c @@ -110,3 +110,12 @@ UTILS_copyRecipientsFromJvm(JNIEnv* env, jlongArray recipients, return len; } + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/jni/gpgmeutils.h b/jni/gpgmeutils.h index d6fb803..9248cbc 100644 --- a/jni/gpgmeutils.h +++ b/jni/gpgmeutils.h @@ -44,3 +44,12 @@ inline static jlong _jlongFromPtr(void* p) return (jlong)(unsigned long) p; } #endif + +/* + * Local Variables: + * tab-width: 4; + * c-basic-offset: 4; + * c-file-style: k&r; + * indent-tabs-mode: nil; + * End: + */ diff --git a/src/com/freiheit/gnupg/GnuPGContext.java b/src/com/freiheit/gnupg/GnuPGContext.java index c9e3c51..5fd3b8e 100644 --- a/src/com/freiheit/gnupg/GnuPGContext.java +++ b/src/com/freiheit/gnupg/GnuPGContext.java @@ -852,3 +852,5 @@ private native void gpgmeCtxSetEngineInfo(long context, int proto, String fileNa private native void gpgmeSetTextmode(long l, boolean state); } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGData.java b/src/com/freiheit/gnupg/GnuPGData.java index 57c4172..c85ddfd 100644 --- a/src/com/freiheit/gnupg/GnuPGData.java +++ b/src/com/freiheit/gnupg/GnuPGData.java @@ -169,3 +169,5 @@ public int size() { private native void gpgmeDataRead(long data, InputStream in) throws IOException; } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGException.java b/src/com/freiheit/gnupg/GnuPGException.java index 4ff7c95..1884e7b 100644 --- a/src/com/freiheit/gnupg/GnuPGException.java +++ b/src/com/freiheit/gnupg/GnuPGException.java @@ -34,3 +34,5 @@ public class GnuPGException extends RuntimeException { super(msg); } } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGGenkeyResult.java b/src/com/freiheit/gnupg/GnuPGGenkeyResult.java index b06941d..9e9b4ba 100644 --- a/src/com/freiheit/gnupg/GnuPGGenkeyResult.java +++ b/src/com/freiheit/gnupg/GnuPGGenkeyResult.java @@ -79,3 +79,5 @@ public boolean isSub() { return _sub; } } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGKey.java b/src/com/freiheit/gnupg/GnuPGKey.java index 860410c..f0845ae 100644 --- a/src/com/freiheit/gnupg/GnuPGKey.java +++ b/src/com/freiheit/gnupg/GnuPGKey.java @@ -295,3 +295,5 @@ protected void finalize() { private native boolean gpgmeHasSecretKey(long keyptr); } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGPeer.java b/src/com/freiheit/gnupg/GnuPGPeer.java index 5dcf9cf..136e3e8 100644 --- a/src/com/freiheit/gnupg/GnuPGPeer.java +++ b/src/com/freiheit/gnupg/GnuPGPeer.java @@ -41,3 +41,5 @@ protected long getInternalRepresentation() { return _internalRepresentation; } } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/GnuPGSignature.java b/src/com/freiheit/gnupg/GnuPGSignature.java index 3dc5627..568778d 100644 --- a/src/com/freiheit/gnupg/GnuPGSignature.java +++ b/src/com/freiheit/gnupg/GnuPGSignature.java @@ -191,3 +191,5 @@ protected GnuPGSignature getNextSignature() { private native long gpgmeGetNextSignature(long l); } + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ diff --git a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java index 75492d4..dca4169 100644 --- a/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java +++ b/src/com/freiheit/gnupg/tests/GnuPGTestSuite.java @@ -286,10 +286,5 @@ public void testEncrypt() { // } } -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * compile-command: "ant -emacs -find build.xml" - * End: - */ + +/* Local Variables: tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; End: */ From de1fb1a525200bad803a246338c8ca8b8e3c3325 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 24 Mar 2014 22:30:50 -0400 Subject: [PATCH 80/90] update JNI build for GNU/Linux, Windows, and a partial Mac OS X The same Makefile is now setup to handle multiple platforms. It currently works with Debian/Ubuntu/Mint/etc. and Windows with MinGW. --- README.md | 22 ++++++++++++++++++ jni/GNUmakefile | 60 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c76f62e..d273b02 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,28 @@ the jar and extend the loading mechanism to load a DLL on a Windows platform instead of loading a .so lib. +## Setup for Building + +### Debian/Ubuntu/Mint/etc + + sudo apt-get install default-jdk make ant build-essential \ + libgpgme11-dev libgpg-error-dev + + +### Windows + +* Install MinGW (for 32-bit): http://mingw.org/ +* Install Gpg4win: http://gpg4win.org/download.html +** Signing Key Fingerprint: `61AC 3F5E E4BE 593C 13D6 8B1E 7CBD 620B EC70 B1B8` + + +### Mac OS X + +You need to install GnuPG2 from one of a couple sources. You can get +it from Homebrew, MacPorts, or Fink. Or you can install +"GPGTools":https://gpgtools.org and then build gpgme from source. + + ## Building To build the gnupg-for-java.jar in build/jar/, run this: diff --git a/jni/GNUmakefile b/jni/GNUmakefile index 7987b7e..061ec49 100644 --- a/jni/GNUmakefile +++ b/jni/GNUmakefile @@ -1,37 +1,67 @@ -# to override this JAVA_HOME, use the `-e' flag to make, or call it like: -# make JAVA_HOME=/opt/java -JAVA_HOME := $(shell readlink -f /usr/bin/javac | sed "s:/bin/javac::") -GNUPG_LIB := ../lib/libgnupg-for-java.so JNISRC := GnuPGContext.c GnuPGData.c GnuPGGenkeyResult.c GnuPGKey.c GnuPGSignature.c JNI_CLASSES := $(patsubst %.c, com.freiheit.gnupg.%, $(JNISRC)) JNI_HEADERS := $(patsubst %.c, com_freiheit_gnupg_%.h, $(JNISRC)) SOURCES := $(JNISRC) gpgmeutils.c OBJECTS := $(SOURCES:.c=.o) +JAVA_BUILD := ../build/classes + +DEBUG := -g +ALL_CFLAGS := -Werror -Wall -Wno-deprecated-declarations -fPIC +ALL_CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ + -I"$(JAVA_HOME)/include" + +UNAME := $(shell uname -s) +ifeq (MINGW,$(findstring MINGW,$(UNAME))) + CC := mingw32-gcc + ALL_CFLAGS += -mms-bitfields -Wl,--add-stdcall-alias + ALL_CPPFLAGS += -I"$(JAVA_HOME)/include/win32" -I"$(PROGRAMFILES)/GNU/GnuPG/include" + ALL_LDFLAGS := -s -shared -Wl,--enable-auto-import + ALL_LIBS := -L"$(PROGRAMFILES)/GNU/GnuPG" -lgpgme-11 + JAVA_HOME := $(PROGRAMFILES)/Java/jdk1.7.0_51 + GNUPG_LIB := ../lib/gnupg-for-java.dll +else + ifeq ($(UNAME),Darwin) + CC := gcc + ALL_CPPFLAGS += -I/usr/local/MacGPG2/include + ALL_LDFLAGS := -dylib + ALL_LIBS := -L/usr/local/MacGPG2/lib -framework MacGPGME + JAVA_HOME := $(shell /usr/libexec/java_home \ + || echo /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home) + GNUPG_LIB := ../lib/libgnupg-for-java.dylib + else + CC := gcc + ALL_CFLAGS += $(shell gpgme-config --cflags) + ALL_CPPFLAGS += -I"$(JAVA_HOME)/include/linux" + ALL_LDFLAGS := -shared + ALL_LIBS := $(shell gpgme-config --thread=pthread --libs) + GNUPG_LIB := ../lib/libgnupg-for-java.so + # to override this JAVA_HOME, use the `-e' flag to make, or call it like: + # make JAVA_HOME=/opt/java + JAVA_HOME := $(shell readlink -f /usr/bin/javac | sed "s:/bin/javac::") + endif +endif + +ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) +ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) +ALL_LIBS := $(LIBS) $(ALL_LIBS) + + JAVAP := $(JAVA_HOME)/bin/javap JAVAH := $(JAVA_HOME)/bin/javah JAVA := $(JAVA_HOME)/bin/java -CC := gcc INSTALL := install -m 644 -DEBUG := -g -CFLAGS := -Werror -Wall -Wno-deprecated-declarations \ - -fPIC $(shell gpgme-config --cflags) -CPPFLAGS = -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -DLARGEFILE_SOURCE=1 \ - -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux - -JAVA_BUILD := ../build/classes -LDFLAGS := $(shell gpgme-config --thread=pthread --libs) $(GNUPG_LIB): $(OBJECTS) - $(CC) $(DEBUG) -shared $(CFLAGS) $^ -o $@ $(LDFLAGS) + $(CC) $(DEBUG) $(ALL_CFLAGS) $(ALL_LDFLAGS) $^ -o $@ $(ALL_LIBS) $(OBJECTS): $(SOURCES) gpgmeutils.h %.o: %.c - $(CC) $(DEBUG) $(CFLAGS) $(CPPFLAGS) -c $< + $(CC) $(DEBUG) $(ALL_CFLAGS) $(ALL_CPPFLAGS) -c $< lib: $(GNUPG_LIB) From d69a6bb106f19fe8216b75385969f03c10858202 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 24 Mar 2014 22:31:06 -0400 Subject: [PATCH 81/90] generate and build against JNI headers so definitions match javah generates C headers from the Java sources, so they provide a way to check that the C JNI code matches the Java definitions. This commit enables that functionality. --- README.md | 4 ---- build.xml | 8 ++++---- jni/GNUmakefile | 2 +- jni/GnuPGContext.c | 13 +++++++------ jni/GnuPGData.c | 4 ++-- jni/GnuPGGenkeyResult.c | 3 ++- jni/GnuPGKey.c | 4 ++-- jni/GnuPGSignature.c | 3 ++- 8 files changed, 20 insertions(+), 21 deletions(-) mode change 100644 => 100755 jni/GNUmakefile diff --git a/README.md b/README.md index d273b02..a24612c 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,6 @@ If you want the optional javadoc in build/docs/, run: ant javadoc -For the JNI headers, run: - - make -C jni/ headers - ## Hacking Notes diff --git a/build.xml b/build.xml index b32db15..88dc1dc 100644 --- a/build.xml +++ b/build.xml @@ -19,7 +19,7 @@ - + + - @@ -44,12 +46,12 @@ - + - + @@ -59,8 +61,8 @@ + - @@ -70,8 +72,8 @@ + - @@ -80,20 +82,18 @@ - - - - + + + -