Cipherpack v1.2.0-dirty
A Cryprographic Stream Processor
CPFactory.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24package org.cipherpack;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.net.URL;
29import java.security.PrivilegedAction;
30import java.util.Enumeration;
31import java.util.Iterator;
32import java.util.Properties;
33import java.util.Set;
34import java.util.concurrent.atomic.AtomicBoolean;
35import java.util.jar.Attributes;
36import java.util.jar.Manifest;
37
38import org.jau.util.VersionUtil;
39
40/**
41 * Cipherpack Factory, called by automatically to load the native library.
42 * <p>
43 * Further provides access to certain property settings,
44 * see {@link #DEBUG}, {@link #VERBOSE}.
45 * </p>
46 */
47public class CPFactory {
48
49 /**
50 * Manifest's {@link Attributes.Name#SPECIFICATION_VERSION} or {@code null} if not available.
51 */
52 public static final String getAPIVersion() { return APIVersion; }
53 private static String APIVersion;
54
55 /**
56 * Manifest's {@link Attributes.Name#IMPLEMENTATION_VERSION} or {@code null} if not available.
57 */
58 public static final String getImplVersion() { return ImplVersion; }
59 private static String ImplVersion;
60
61 /**
62 * Verbose logging enabled or disabled.
63 * <p>
64 * System property {@code org.cipherpack.verbose}, boolean, default {@code false}.
65 * </p>
66 */
67 public static final boolean VERBOSE;
68
69 /**
70 * Debug logging enabled or disabled.
71 * <p>
72 * System property {@code org.cipherpack.debug}, boolean, default {@code false}.
73 * </p>
74 */
75 public static final boolean DEBUG;
76
77 /**
78 * True if jaulib {@link org.jau.sys.PlatformProps} has been detected.
79 */
80 public static final boolean JAULIB_AVAILABLE;
81
82 /**
83 * True if jaulib {@link #JAULIB_AVAILABLE} and its {@link org.jau.sys.PlatformProps#USE_TEMP_JAR_CACHE} is true,
84 * i.e. the jar cache is available, enabled and in use.
85 */
86 public static final boolean JAULIB_JARCACHE_USED;
87
88 /**
89 * Deprecated call to {@link java.security.AccessController#doPrivileged(PrivilegedAction)} w/o warnings.
90 * @param <T>
91 * @param o
92 * @return
93 */
94 @SuppressWarnings({ "deprecation", "removal" })
95 public static <T> T doPrivileged(final PrivilegedAction<T> o) {
96 return java.security.AccessController.doPrivileged( o );
97 }
98
99 private static final String implementationNativeLibraryBasename = "cipherpack";
100 private static final String javaNativeLibraryBasename = "javacipherpack";
101
102 private static AtomicBoolean initializedID = new AtomicBoolean(false);
103
104 static {
105 {
106 final String v = System.getProperty("org.cipherpack.debug", "false");
107 DEBUG = Boolean.valueOf(v);
108 }
109 if( DEBUG ) {
110 VERBOSE = true;
111 } else {
112 final String v = System.getProperty("org.cipherpack.verbose", "false");
113 VERBOSE = Boolean.valueOf(v);
114 }
115
116 boolean isJaulibAvail = false;
117 try {
118 isJaulibAvail = null != Class.forName("org.jau.sys.RuntimeProps", true /* initializeClazz */, CPFactory.class.getClassLoader());
119 } catch( final Throwable t ) {
120 if( DEBUG ) {
121 System.err.println("CPFactory Caught: "+t.getMessage());
122 t.printStackTrace();
123 }
124 }
125 JAULIB_AVAILABLE = isJaulibAvail;
126
127 if( isJaulibAvail ) {
128 JAULIB_JARCACHE_USED = org.jau.sys.RuntimeProps.USE_TEMP_JAR_CACHE;
129 } else {
130 JAULIB_JARCACHE_USED = false;
131 }
132 if( VERBOSE ) {
133 System.err.println("Jaulib available: "+JAULIB_AVAILABLE+", JarCache in use: "+JAULIB_JARCACHE_USED);
134 }
135
136 final ClassLoader cl = CPFactory.class.getClassLoader();
137 boolean libsLoaded = false;
138 if( JAULIB_AVAILABLE ) {
140 try {
141 org.jau.pkg.JNIJarLibrary.addNativeJarLibs(new Class<?>[] { CPFactory.class }, null);
142 } catch (final Exception e0) {
143 System.err.println("CPFactory Caught "+e0.getClass().getSimpleName()+": "+e0.getMessage()+", while JNILibLoaderBase.addNativeJarLibs(..)");
144 if( DEBUG ) {
145 e0.printStackTrace();
146 }
147 }
148 }
149 try {
150 if( null != org.jau.sys.dl.NativeLibrary.open(implementationNativeLibraryBasename,
151 true /* searchSystemPath */, false /* searchSystemPathFirst */, cl, true /* global */) )
152 {
153 org.jau.sys.JNILibrary.loadLibrary(javaNativeLibraryBasename, false, cl);
154 libsLoaded = true;
155 }
156 } catch (final Throwable t) {
157 System.err.println("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+", while loading libs..");
158 if( DEBUG ) {
159 t.printStackTrace();
160 }
161 }
162 if( DEBUG ) {
163 System.err.println("Jaulib: Native libs loaded: "+ libsLoaded);
164 }
165 }
166 if( !libsLoaded ) {
167 try {
168 final Throwable[] t = { null };
169 if( !PlatformToolkit.loadLibrary(implementationNativeLibraryBasename, cl, t) ) {
170 throw new RuntimeException("Couldn't load native tool library with basename <"+implementationNativeLibraryBasename+">", t[0]);
171 }
172 if( !PlatformToolkit.loadLibrary(javaNativeLibraryBasename, cl, t) ) {
173 throw new RuntimeException("Couldn't load native java library with basename <"+javaNativeLibraryBasename+">", t[0]);
174 }
175 } catch (final Throwable e) {
176 System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage()+", while loading libs (2) ..");
177 if( DEBUG ) {
178 e.printStackTrace();
179 }
180 throw e; // fwd exception - end here
181 }
182 }
183
184 // Map all Java properties '[org.]cipherpack.*' and 'cipherpack.*' to native environment.
185 try {
186 if( DEBUG ) {
187 System.err.println("CPFactory: Mapping '[org.|jau.]cipherpack.*' properties to native environment");
188 }
189 final Properties props = doPrivileged(new PrivilegedAction<Properties>() {
190 @Override
191 public Properties run() {
192 return System.getProperties();
193 } });
194
195 final Enumeration<?> enums = props.propertyNames();
196 while (enums.hasMoreElements()) {
197 final String key = (String) enums.nextElement();
198 if( key.startsWith("org.cipherpack.") || key.startsWith("jau.cipherpack.") ||
199 key.startsWith("cipherpack.") )
200 {
201 final String value = props.getProperty(key);
202 if( DEBUG ) {
203 System.err.println(" <"+key+"> := <"+value+">");
204 }
205 setenv(key, value, true /* overwrite */);
206 }
207 }
208 } catch (final Throwable e) {
209 System.err.println("Caught exception while forwarding system properties: "+e.getMessage());
210 e.printStackTrace();
211 }
212
213 try {
214 final Manifest manifest = getManifest(cl, new String[] { "org.cipherpack" } );
215 final Attributes mfAttributes = null != manifest ? manifest.getMainAttributes() : null;
216
217 // major.minor must match!
218 final String NAPIVersion = getNativeAPIVersion();
219 final String JAPIVersion = null != mfAttributes ? mfAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION) : null;
220 if ( null != JAPIVersion && JAPIVersion.equals(NAPIVersion) == false) {
221 final String[] NAPIVersionCode = NAPIVersion.split("\\D");
222 final String[] JAPIVersionCode = JAPIVersion.split("\\D");
223 if (JAPIVersionCode[0].equals(NAPIVersionCode[0]) == false) {
224 if (Integer.valueOf(JAPIVersionCode[0]) < Integer.valueOf(NAPIVersionCode[0])) {
225 throw new RuntimeException("Java library "+JAPIVersion+" < native library "+NAPIVersion+". Please update the Java library.");
226 } else {
227 throw new RuntimeException("Native library "+NAPIVersion+" < java library "+JAPIVersion+". Please update the native library.");
228 }
229 } else if (JAPIVersionCode[1].equals(NAPIVersionCode[1]) == false) {
230 if (Integer.valueOf(JAPIVersionCode[1]) < Integer.valueOf(NAPIVersionCode[1])) {
231 throw new RuntimeException("Java library "+JAPIVersion+" < native library "+NAPIVersion+". Please update the Java library.");
232 } else {
233 throw new RuntimeException("Native library "+NAPIVersion+" < java library "+JAPIVersion+". Please update the native library.");
234 }
235 }
236 }
237 initializedID.set( true ); // initialized!
238
239 APIVersion = JAPIVersion;
240 ImplVersion = null != mfAttributes ? mfAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION) : null;
241 if( VERBOSE ) {
242 System.err.println("Cipherpack loaded");
243 System.err.println("Cipherpack java api version "+JAPIVersion);
244 System.err.println("Cipherpack native api version "+NAPIVersion);
245 if( null != mfAttributes ) {
246 final Attributes.Name[] versionAttributeNames = new Attributes.Name[] {
247 Attributes.Name.SPECIFICATION_TITLE,
248 Attributes.Name.SPECIFICATION_VENDOR,
249 Attributes.Name.SPECIFICATION_VERSION,
250 Attributes.Name.IMPLEMENTATION_TITLE,
251 Attributes.Name.IMPLEMENTATION_VENDOR,
252 Attributes.Name.IMPLEMENTATION_VERSION,
253 new Attributes.Name("Implementation-Commit") };
254 for( final Attributes.Name an : versionAttributeNames ) {
255 System.err.println(" "+an+": "+mfAttributes.getValue(an));
256 }
257 } else {
258 System.err.println(" No Manifest available;");
259 }
260 }
261 } catch (final Throwable e) {
262 System.err.println("Error querying manifest information.");
263 e.printStackTrace();
264 throw e; // fwd exception - end here
265 }
266
267 }
268
269 public static void checkInitialized() {
270 if( false == initializedID.get() ) {
271 throw new IllegalStateException("Cipherpack not initialized.");
272 }
273 }
274 public static boolean isInitialized() {
275 return false != initializedID.get();
276 }
277
278 public static synchronized void initLibrary() {
279 // tagging static init block
280 }
281
282 /**
283 * Helper function to retrieve a Manifest instance.
284 */
285 public static final Manifest getManifest(final ClassLoader cl, final String[] extensions) {
286 final Manifest[] extManifests = new Manifest[extensions.length];
287 try {
288 final Enumeration<URL> resources = cl.getResources("META-INF/MANIFEST.MF");
289 while (resources.hasMoreElements()) {
290 final URL resURL = resources.nextElement();
291 if( DEBUG ) {
292 System.err.println("resource: "+resURL);
293 }
294 final InputStream is = resURL.openStream();
295 final Manifest manifest;
296 try {
297 manifest = new Manifest(is);
298 } finally {
299 try {
300 is.close();
301 } catch (final IOException e) {}
302 }
303 final Attributes attributes = manifest.getMainAttributes();
304 if(attributes != null) {
305 final String attributesExtName = attributes.getValue( Attributes.Name.EXTENSION_NAME );
306 for(int i=0; i < extensions.length && null == extManifests[i]; i++) {
307 final String extension = extensions[i];
308 if( extension.equals( attributesExtName ) ) {
309 if( 0 == i ) {
310 return manifest; // 1st one has highest prio - done
311 }
312 extManifests[i] = manifest;
313 }
314 }
315 }
316 }
317 } catch (final IOException ex) {
318 throw new RuntimeException("Unable to read manifest.", ex);
319 }
320 for(int i=1; i<extManifests.length; i++) {
321 if( null != extManifests[i] ) {
322 return extManifests[i];
323 }
324 }
325 return null;
326 }
327
328 public static void main(final String args[]) {
329 System.err.println("Jaulib: Available "+JAULIB_AVAILABLE+", JarCache in use "+JAULIB_JARCACHE_USED);
330 if( JAULIB_AVAILABLE ) {
331 System.err.println(VersionUtil.getPlatformInfo());
332 System.err.println("Version Info:");
333 final CPVersion v = CPVersion.getInstance();
334 System.err.println(v);
335 System.err.println("");
336 System.err.println("Full Manifest:");
337 System.err.println(v.getFullManifestInfo(null));
338 } else {
339 System.err.println("Full Manifest:");
340 final Manifest manifest = getManifest(CPFactory.class.getClassLoader(), new String[] { "org.cipherpack" } );
341 final Attributes attr = manifest.getMainAttributes();
342 final Set<Object> keys = attr.keySet();
343 final StringBuilder sb = new StringBuilder();
344 for(final Iterator<Object> iter=keys.iterator(); iter.hasNext(); ) {
345 final Attributes.Name key = (Attributes.Name) iter.next();
346 final String val = attr.getValue(key);
347 sb.append(" ");
348 sb.append(key);
349 sb.append(" = ");
350 sb.append(val);
351 sb.append(System.lineSeparator());
352 }
353 System.err.println(sb);
354 }
355 try {
356 // FIXME
357 } catch ( final Throwable t ) {
358 t.printStackTrace();
359 }
360 }
361
362 public native static String getNativeVersion();
363 public native static String getNativeAPIVersion();
364 private native static void setenv(String name, String value, boolean overwrite);
365}
366
367/** \example Cipherpack.java
368 * This is the commandline version to convert a source from and to a cipherpack, i.e. encrypt and decrypt.
369 */
370
371/** \example Test01Cipherpack.java
372 * Unit test, testing encrypting to and decrypting from a cipherpack stream using different sources.
373 *
374 * Unit test also covers error cases.
375 */
Cipherpack Factory, called by automatically to load the native library.
Definition: CPFactory.java:47
static final Manifest getManifest(final ClassLoader cl, final String[] extensions)
Helper function to retrieve a Manifest instance.
Definition: CPFactory.java:285
static native String getNativeVersion()
static final boolean JAULIB_JARCACHE_USED
True if jaulib JAULIB_AVAILABLE and its org.jau.sys.PlatformProps#USE_TEMP_JAR_CACHE is true,...
Definition: CPFactory.java:86
static final boolean JAULIB_AVAILABLE
True if jaulib org.jau.sys.PlatformProps has been detected.
Definition: CPFactory.java:80
static native String getNativeAPIVersion()
static void checkInitialized()
Definition: CPFactory.java:269
static final String getImplVersion()
Manifest's Attributes.Name#IMPLEMENTATION_VERSION or null if not available.
Definition: CPFactory.java:58
static boolean isInitialized()
Definition: CPFactory.java:274
static final String getAPIVersion()
Manifest's Attributes.Name#SPECIFICATION_VERSION or null if not available.
Definition: CPFactory.java:52
static synchronized void initLibrary()
Definition: CPFactory.java:278
static final boolean VERBOSE
Verbose logging enabled or disabled.
Definition: CPFactory.java:67
static< T > T doPrivileged(final PrivilegedAction< T > o)
Deprecated call to java.security.AccessController#doPrivileged(PrivilegedAction) w/o warnings.
Definition: CPFactory.java:95
static void main(final String args[])
Definition: CPFactory.java:328
static final boolean DEBUG
Debug logging enabled or disabled.
Definition: CPFactory.java:75
This jaulib derived version info class is only usable when having jaulib available,...
Definition: CPVersion.java:41
static CPVersion getInstance()
Returns a transient new instance.
Definition: CPVersion.java:84