Use encryption technology to protect JAVA source code

xiaoxiao2021-03-05  22

The source code of the Java program is easily peeled by others. As long as there is an anti-compiler, anyone can analyze the code of others. This article discusses how to protect source code by encryption technology without modifying the original program. First, why do you want to encrypt? For languages ​​such as traditional C or C , it is easy to protect source code on the web, as long as it does not release it. Unfortunately, the source code of the Java program is easily peeked by others. As long as there is an anti-compiler, anyone can analyze the code of others. The flexibility of Java makes the source code are easily stealing, but at the same time, it also makes it relatively easy to encrypt the code, and the only thing we need to know is Java's ClassLoader object. Of course, in the encryption process, knowledge about Java Cryptography Extension (JCE) is essential. There are several technologies that can "fuzzy" Java files that make the anti-compiler handle the effect of the class file. However, modifying the anti-compiler makes it possible to handle these fuzzy-processed class files, so it is not easy to rely on fuzzy techniques to ensure the security of the source code. We can encrypt applications, such as PGP (PRETTY Good Privacy) or GPG (GNU Privacy Guard). At this time, the end user must first decrypt before running the application. But after decryption, the end user has a non-encrypted class file, which does not differ in advance. The mechanism of Java runtime installation is implicitly implicitly implicitly modified. JVM requires an object called ClassLoad every time you load a class file, which is responsible for putting new classes into running JVM. JVM gives the ClassLoader a string containing the name of the name (such as a java.lang.object), then by the ClassLoader to find the class file, load the original data, and convert it into a Class object. We can modify it before the class file is executed by custom ClassLoader. This technology is very wide - here, its use is to decrypt when the class file is loaded, so it can be seen as an instant decryption device. Since the decrypted bytecode file will never save to the file system, the screwdriver is hard to get the decrypted code. Since the process of converting the original byte code into a Class object is completely responsible for the system, create a custom ClassLoader object is not difficult, just get the original data first, then you can make any conversion in the decryption. Java 2 simplifies custom ClassLoader builds to a certain extent. In Java 2, LoadClass's default implementation is still responsible for processing all required steps, but in order to take into account various customized class equipment, it also calls a new FindClass method. This provides a shortcut to our customized ClassLoader, which reduces trouble: just override FindClass instead of overwriting loadingClass. This approach avoids the public steps necessary to repeat all loaders because all of this is responsible by loadingClass. However, the custom ClassLoader herein does not use this method. the reason is simple. If you look for encrypted class files by the default classloader, it can be found; but because the class file has been encrypted, it will not recognize this class file, and the load process will fail. Therefore, we must implement loadclass themselves, and some workload has increased slightly. Second, the custom-made loader Every running JVM already has a ClassLoader. This default ClassLoader is looking for a suitable bytecode file in a local file system based on the value of the ClassPath environment variable.

Application Custom ClassLoader requires a more in-depth understanding of this process. We must first create an instance of custom ClassLoader classes, and then explicitly require it to load another class. This enables the JVM to associate this class and all the classes they need to customized ClassLoader. Listing 1 shows how to load class files with custom ClassLoader. [Listing 1: Use custom ClassLoader load class files] // First create a ClassLoader object classloader myclassloader = new myclassloader (); // Using custom ClassLoader objects to load class files / / and convert it into Class object class myclass = MyclassLoader.loadClass ("MyPackage.Myclass"); // Finally, create an instance of this class Object newInstance (); // Note that all other classes needed by MyClass will pass // custom ClassLoader Automatic loading

As mentioned earlier, custom ClassLoad is just acquire data of class files, and then pass the byte code to the runtime system, which completes the remaining tasks by the latter. ClassLoader has several important ways. When you create a custom ClassLoader, we only need to overwrite one of them, that is, LoadClass, providing code for obtaining the original class file data. This method has two parameters: the name of the class, and a mark indicating whether the JVM requires the parsing class name (ie, whether it is equally loaded with a dependency). If this tag is True, we only need to call ResolVeclass before returning JVM. [Listing 2: ClassLoader.loadClass () A simple implementation] Public class loadclass (String name, boolean resolve) throws classnotfoundexception {Try {// We want to create a class object class clasz = null; // Required Step 1: If Class is already in the system buffer, // We don't have to load it again Clasz = FindloadedClass (Name); if (CLASZ! = NULL) Return Clasz; // below is the custom section Byte classData [] = / * through a method Get the bytecode data * /; if (ClassData! = Null) {// Successfully read bytecode data, now convert it into a Class object Clasz = defineclass (name, classdata, 0, classdata.length);} / / Essential Step 2: If there is no success, // we try to load it with the default ClassLoad to put it if (Clasz == null) Clasz = FINDSYSTEMCLASS (Name); // Required step 3: If necessary, Enter the related class IF (Resolve && Clasz! = NULL) ResolVeclass (CLASZ); // Return the class to the caller return clasz;} catch (ioException ie) {throw new classnotfoundexception (IE.toTString ());} catch GeneralsecurityException GSE) {throw new classnotfoundexception (gse.tostring ());}} Listing 2 shows a simple loadClass implementation. Most of the code is the same for all ClassLoader objects, but there is a small part (marked by comment marks). During the processing, the ClassLoader object is used to use several other auxiliary methods: FindloadedClass: Used to check to confirm that the requested class does not currently exist. The LoadClass method should first call it. DefineClass: After getting the original class file number data, call DefineClass to convert it into a Class object. Any LoadClass implementation must call this method. FindsystemClass: Provides support for default ClassLoader. If the custom method used to find the class cannot find the specified class (or intentionally do not customize the custom method), you can call the method to try the default loading method. This is useful, especially when loading standard Java classes from ordinary JAR files.

ResolVeclass: When JVM wants to load, not only  ㄖ ǖ 啵 啵  ǜ ǜ ǜ 嘁   乃  渌  嗍 嗍 嗍.   乃 乃    .................... At this time, we must call ResolVeclass before returning to the originally loaded CLASS object to call the caller. Third, encryption, decryption, Java encryption, Java Cryptography Extension, referred to as JCE. It is Sun's encryption service software that includes encryption and key generation functions. JCE is an extension of JAVA CRYPTOGRAPHY ARCHITECTURE. JCE does not specify a specific encryption algorithm, but provides a framework, and the specific implementation of the encryption algorithm can be added as a service provider. In addition to the JCE framework, the JCE package also includes a SunJCE service provider, including many useful encryption algorithms, such as DES (Data Encryption Standard) and Blowfish. For a simple meter, in this article we will encrypt and decrypt by the DES algorithm. Below is the basic steps that must be followed by JCE encryption and decryption data: Step 1: Generate a secure key. There is a key before encrypt or decrypt any data. The key is a small data released with the encrypted application, and Listing 3 shows how to generate a key. [Listing 3: Generate a key] // DES algorithm requires a trusted random number SECURANDOM SR = New SecurerandM (); // Generate a keygenerator object for our choice of the des algorithm KeyGenerator kg = keygenerator.getInstance (" "); Kg.init (sr); // generated key secretkey key = kg.generateKey (); // Get a key data byte rawkeydata [] = key.Getencoded (); / * Next, you can use it Sposter Encrypted or decrypt, or save it as file for later use * / dosomething (RawkeyData); Step 2: Encrypt data. After getting a key, you can use it to encrypt the data. In addition to decrypting ClassLoader, there is generally a separate program that encrypts the application (see Listing 4).

[Listing 4: Primitive data with key encryption] // DES algorithm requires a trusted random number SECURANDOM SR = New Securerandom (); Byte RawkeyData [] = / * Get key data in some way * /; // Create from original key data objects DESKeySpec DESKeySpec dks = new DESKeySpec (rawKeyData); // Create a factory key, and then use it to convert into // a DESKeySpec SecretKey objects SecretKeyFactory keyFactory = SecretKeyFactory.getInstance ( "DES") SecretKey Key = KeyFactory.GenerateSecret (DKS); // Cipher object actually completed encryption operation cipher cipher = copher.getInstance ("des"); // initialize the Cipher object Cipher object Cipher object (Cipher.Encrypt_Mode, KEY, SR) ); // Now obtain data and encrypt byte data [] = / * Get data * / / / / officially perform encrypted operation byte encryptedData [] = cipher.dofinal (data); // further process after encryption Data DOSMETHING (EncryptedData); Step 3: Decipher the data. ClassLoader analyzes and decrypts class files when running encrypted applications. The steps are shown in Listing 5. [Listing 5: Decryption Decryption Data] // DES Algorithm requires a trusted random number SECURANDOM SR = new securerandom (); byte rawkeyData [] = / * Get the original key data in some way * /; // Create a DESKeySpec DESKeySpec objects from DKS original key data = new DESKeySpec (rawKeyData); // Create a factory key, and then use it to convert the object into // a DESKeySpec SecretKey objects SecretKeyFactory keyFactory = SecretKeyFactory.getInstance ( "DES "); SecretKey key = keyfactory.generateSecret (DKS); // Cipher object actually completed decryption operation cipher cipher = copher.getInstance (" des "); // Initialize Cipher object copher.init (Cipher.Decrypt_mode, Key); , SR; // Now obtain data and decrypt byte encryptedData [] = / * Get encrypted data * / / officially perform decryption operation Byte decryptedData [] = cipher.dofinal (encryptedData); // further process after decryption Data DOSMETHING (DecryptedData); 4, the application instance describes how to encrypt and decrypt data. To deploy an encrypted application, the steps are as follows: Step 1: Create an application. Our example contains an App main class, two auxiliary classes (known as Foo and Bar, respectively). There is no practical function of this app, but as long as we can encrypt this app, encrypting other applications will not be in. Step 2: Generate a security key.

In the command line, write the key to a file using the GenerateKey Tool (see GenerateKey.java):% Java GenerateKey Key.DATA Step 3: Encryption App. In the command line, use the EncryptClasses tool (see EncryptClasses.java) Class:% java encryptclasses key.data app.class foo.class bar.class This command replaces each .class file with their respective encryption versions. Step 4: Run the encrypted application. The user runs encrypted applications through a DecryptStart program. DecryptStart programs are shown in Listing 6. [Listing 6: DecryptStart.java, launching the program that is encrypted] IMPORT JAVA.IO. *; import java.security. *; Import java.lang.reflect. *; Import javax.crypto. *; Import javax.crypto. Spec. *; public class decryptStart Extends ClassLoader {// These objects are set in the constructor, and the loadClass () method will use them to decrypt the class private secretKey key; private cipher cipher; // constructor: Set the decryption required Object public DecryptStart (SecretKey key) throws GeneralSecurityException, IOException {this.key = key; String algorithm = "DES"; SecureRandom sr = new SecureRandom (); System.err.println ( "[DecryptStart: creating cipher]"); cipher = Cipher.GetInstance (Algorithm); cipher.init (Cipher.Decrypt_mode, key, sr);} // main process: We want to read the key here, create DecryptStart // instance, which is our custom ClassLoader.

// After setting ClassLoader, we use it to load application instance, // Finally, we call the application instance of the application instance through the Java Reflection API Static Public Void Main (String Args []) throws exception {string keyfilename = args [0] String appname = args [1]; // These are the parameters passed to the application itself String Reaargs [] = new string [args.length-2]; System.ArrayCopy (Args, 2, Reaargs, 0, args.length- 2); // read key System.err.println ( "[DecryptStart: reading key]"); byte rawKey [] = Util.readFile (keyFilename); DESKeySpec dks = new DESKeySpec (rawKey); SecretKeyFactory keyFactory = SecretKeyFactory .GETINSTANCE ("DES"); SecretKey Key = KeyFactory.GenerateSecret (DKS); // Create Decryption ClassLoader DecryptStart DR = New DecryptStart (key); // Create an instance of the application main class / / Plug it by ClassLoader SYSTEM .rr.println ("[DecryptStart: Loading" AppName "]"); Class Clasz = Dr.LoadClass (AppName); // Finally, the main () method // obtains a main () method // get a pair = new string [1]; class maings [] = {(new string [1]). getClass ()}; method main = clasz.getMethod ("main", maings); / / Create an array Obje containing main () method parameters CT argsArray [] = {reaargs}; system.err.println ("[decryptstart: running" appname ". main ()]"); // Call main () main.invoke (null, argsarray);} public class LoadClass (String Name, Boolean Resolve) throws classnotfoundexception {Try {// We want to create a class object class clasz = null; / / Required step 1: If the class is already in the system buffer // We don't have to load it again Clasz = FindloadedClass (Name); if (Clasz! = NULL)          = Util.Readfile (Name ". Class") ;         = NULL {                                                                                                                                     

Cipher.dofinal (ClassData);                                                                                                                                         DecryptStart: Decrypting Class " Name "] ");}}}}} Catch (filenotfoundexception fnfe) {} // Required step 2: If there is no success above // ​​We try to load it with the default ClassLoader (Clasz == NULL) CLASZ = FINDSYSTEMCLASS (NAME); // Required step 3: If necessary, load the associated class IF (Resolve && Clas! = null) ResolVeclass (CLASZ); // Return the class to the caller Return Clasz;} catch (IOException ie) { throw new ClassNotFoundException (ie.toString ());} catch (GeneralSecurityException gse) { new ClassNotFoundException (gse.toString ()) throw;}}} for application without encryption, normal execution mode As follows:% Java App Arg0 Arg1 Arg2 For encrypted applications, the corresponding mode of operation is:% Java DecryptStart Key.Data App Arg0 Arg1 Arg2 DecryptStart has two purposes. An instance of a DecryptStart is a custom ClassLoader that implements instant decryption operations; at the same time, DecryptStart also contains a main process, which creates a decompressed instance and uses it to load and run applications. The code Application App to include app.java, foo.java and bar.java. Util.java is a file I / O tool that uses more examples in this example. Complete code Please download it from this article. 5. Precautions We see that it is easy to encrypt a Java app without modifying the source code. However, there is no fully safe system in the world. This paper provides a certain degree of source code protection, but it is fragile for some attacks. Although the application itself has been encrypted, the starter DecryptStart is not encrypted. An attacker can refactor to build the launcher and modify it, save the decrypted class file to disk. One way to reduce this risk is to perform high quality fuzzy processing on the startup program. Alternatively, the startup program can also be used directly into a machine language, so that the launcher has the security of traditional execution file formats. In addition, it is necessary to remember that most JVM itself is not safe. The hacker may modify the JVM, obtain the decrypted code from the ClassLoader and save to disk, thus bypass the encryption technology of this article. Java did not provide truly effective remedies for this purpose. However, it should be noted that all these possible attacks have a premise, which is the attacker can get a key. If there is no key, the security of the application is entirely on the security of the encryption algorithm. Although this protective code is not perfect, it is still not a valid program for protecting intellectual property and sensitive user data. Reference Resources Update the function module at runtime. This paper introduces a Java program that utilizes the class library loader ClassLoad to update some of the function modules in the runtime, and compares the dynamic link library scheme that implements the same functionality in C / C .

转载请注明原文地址:https://www.9cbs.com/read-32198.html

New Post(0)