None of the implementations that you give in your question are completely correct, and none of the implementations that you give should be used as is. In the future, I will discuss aspects of password-based encryption in Android.
Keys and Hashes
I will start discussing the password system with salts. Salt is a random number. This is not a "conclusion". Implementation 1 includes a generateSalt() method that generates a cryptographically strong random number. Since salt is important for safety, it should be kept secret after its creation, although it needs to be generated only once. If this is a website, then it is relatively easy to keep a secret, but for installed applications (for desktop and mobile devices) it will be much more difficult.
The getHash() method returns the hash of the given password and salt, combined in one line. The SHA-512 algorithm is used, which returns a 512-bit hash. This method returns a hash, which is useful for checking the integrity of the string, so it can also be used by calling getHash() with only a password or just salt, since it simply combines both parameters. Since this method will not be used in a password-based encryption system, I will not discuss it further.
The getSecretKey() method extracts the key from the char array getSecretKey() from the password and the hexadecimal salt returned by getSecretKey() generateSalt() . The algorithm used is PBKDF1 (I think) from PKCS5 with SHA-256 as a hash function and returns a 256-bit key. getSecretKey() generates a key by repeatedly generating hashes of the password, salt, and counter (up to the iteration counter specified in PBE_ITERATION_COUNT , here 100) to increase the time required to mount the attack by brute force. The length of the salt should be at least the length of the generated key, in this case at least 256 bits. The iteration counter should be set as long as possible without causing undue delay. For more information on salts and the number of iterations when obtaining a key, see Section 4 in RFC2898 .
However, an implementation in Java PBE has disadvantages if the password contains Unicode characters, i.e. those that require a representation of more than 8 bits. As stated in PBEKeySpec , "the PBE mechanism defined in PKCS # 5 only considers the lower 8 bits of each character." To work around this problem, you can try to generate a hexadecimal string (which will contain only 8-bit characters) from all 16-bit characters in the password before passing it to PBEKeySpec . For example, "ABC" becomes "004100420043". Also note that PBEKeySpec "asks for the password as an array of characters, so it can be overwritten [using clearPassword() ] after completion." (Regarding “protecting strings in memory,” see this question .) However, I don't see any problems with representing the salt as a hexadecimal string.
encryption
After the key is generated, we can use it to encrypt and decrypt the text. Implementation 1 uses the AES/CBC/PKCS5Padding , i.e., AES in the Cipher Block Chaining (CBC) encryption mode with padding defined in PKCS # 5. (Other AES encryption modes include counter mode (CTR), electronic code book mode (ECB ) and Galois counter mode (GCM). Another question about stack overflows contains answers that discuss in detail the various AES encryption modes that are recommended for use. Remember also that there are several CBC mode encryption attacks, some of which are mentioned in RFC 7457 .)
If the encrypted text will be accessible to outsiders, it is recommended to use a message authentication code or MAC for encrypted data (and, optionally, additional parameters) to protect its integrity (a method known as authenticated encryption with corresponding data, AEAD, is described in RFC 5116). Hash-based MAC addresses or HMAC-based MACs based on SHA-256 or other secure hash functions are popular here. However, if a MAC is used, a secret is used that is at least twice as long as a normal encryption key to avoid attacks on the associated key: the first half serves as the encryption key, and the second half serves as the key for the MAC. (That is, in this case, generate one secret from the password and salt and divide this secret into two parts.)
Java implementation
The various functions in implementation 1 use a particular provider, namely "BC", for their algorithms. In general, however, it is not recommended to request specific providers, since not all providers are available in all Java implementations, whether due to lack of support, to avoid duplication of code, or for other reasons. This tip has become especially important since the release of the Android P preview in early 2018, as some of the features from the "BC" provider are outdated there - see the Android Cryptography Changes article in the Android Developers Blog. See also Introduction to Oracle Providers .
Therefore, PROVIDER should not exist, and the -BC line should be removed from PBE_ALGORITHM . Implementation 2 is correct in this regard.
A method should not catch all exceptions, but only handle those exceptions that it can. The implementations given in your question can throw various checked exceptions. The method can choose to wrap only those checked exceptions with CryptoException or specify these checked exceptions in the throws . For convenience, it may be appropriate to wrap the original exception in a CryptoException, since exception classes could potentially be thrown.
SecureRandom on Android
As described in detail in the article “Some Thoughts on SecureRandom” on the Android Developers Blog, the implementation of java.security.SecureRandom in Android releases prior to 2013 has a flaw that reduces the number of random numbers it delivers. This flaw can be eliminated by passing an unpredictable and random data block (for example, the output of /dev/urandom ) to the setSeed method of this class.