简体   繁体   中英

RSA from Android to PHP

I've been searching all day long(aprox. 12 hours) how to deal with this and couldn't find anything to work for me so I decided to make another question on the topic.

My setup:

  1. Taking credentials from user
  2. Encrypt them using RSA public key and then base64
  3. Send to server
  4. base64_decode, decrypt and check credentials

This is the code I use for encryption on Android:

    public class Encrypter {
        public static PublicKey loadPublicKey(Context context) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
            InputStream is = context.getAssets().open("public_key.txt");
            byte[] bytes = new byte[is.available()];
            is.read(bytes);

            PublicKey publicKey = KeyFactory.getInstance(RSA).generatePublic(
                    new X509EncodedKeySpec(Base64.decode(bytes)));

      return publicKey;
    }

    private static byte[] enc(String text, PublicKey pubRSA) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA);
        cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
        return cipher.doFinal(text.getBytes("UTF-8"));
    }

    public final static String encrypt(String text, PublicKey uk) {
        try {
            return Base64.encodeBytes(enc(text, uk));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

And how I use it:

 String username = "admin";
    PublicKey pubk = Encrypter.getPublicKey(this);
    username = Encrypter.encrypt(username, pubk);

This is my public key without START and END :

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfPDQ7tRqUw8oTPcNG3GR9OyhWnrtQXj2gmzTKdLncPIuolG1GTjYyZO25+cHSgHBlFmc20cKO0uasveZWCwuBTmMY3kVYtVblxUbHmHakLc2CRsKlCA3GAU/OAvfQfzcRUE0O1R138XcTydDGNgWKthqePJz97sEtg8nY55imVUTfRJPOeMvn1/vQQY50OTGniyoI+sh66P/0xpjrZQdIKaNADD5tQbDmrrJjoocC/GuwqBizi7rmU/p/9udNj5hCKqxL6PmejDsHss+UrhBx5t1/iem2yEBhvuOPDyvBPn/ZqAEKeAUKyf+Z5d3XQAlzJq5UjliRM2IA/K6uUBCQIDAQAB

My problem is that if I encrypt it using Android and then Base64.encode it, I get a different string than if I encrypt from PHP using the same public key

I tried encrypting the work "admin" on both sides and here's what I got: String got from Android:

hF8ykDKLYVJOnHE5Uswq0+BasIRqTLnFIjvy2rLxfe/oDJ0GbhjTjoizNuSk2grKbAgkJqFN5uAFuhkqqjyxoSJlJNsQi5QRis9FDUIm1iAhjSD8olTBFky+q1pqYQsQ/Cj+9qSVTnoKpB2oJyeEk2Zx7mYegHKT/yItDtsSLa7fURaxygp1osj0Nz8pas21zXgMIyG2wKARG9IlxdBo4Vl2nj7iKwPCkHMrSeXzFjDsKOkwBzMoPuUUGSFUZ0QbL+b/Ha+Rgdb7oItzTvBfHsoL9m91j20NhqapKRYkJ2pPUhPPVDZtTzO/JPKK4ndzg32w7jKqb9zinOBcilQdGg==

String from PHP:

oh8fNeY8FwPqUkvJhFQr/2IPgdj7XEUNHjc7+KZwRGot+4DIQWtxv3N4UtzbpvkwcgI/kUjXZOz+mNSzvTEVpmZprOWBow/zlbCO7tLgH2Q131gATZdGxPEgOIVbTOWQkXL+d8x+jODnPhaXb8vUB2boQmd70ifBAq2C5mMCGPeA/gRwNquwdEG62W4zvaeXzXc6sXCXXvE6cgaWLOhZWFnLyo2ulFrkGk9XXOaWoS3HYnS35n8xHxulSEeAJOmGgEd56cSbDIlJrD9H5k6mb6PX0/eLoC7J9vdBhdM8nJVviL6NxtiOtDTCWVFb4k9il8Sksz8eascFM8yAB0KvRw==

For encryption in PHP I use phpseclib under Laravel 5.2 framework

Method to check credentials

public function creds_valid(Request $request) {
        $inputs = $request->all();

        $username = $inputs['username'];
        $password = $inputs['password'];

        $private_key = file_get_contents(storage_path() . "/phpseclib/public_key.txt");
        $rsa = new RSA();
        $rsa->loadKey($private_key);

        $username = $rsa->decrypt(base64_decode($username));
        $password = $rsa->decrypt(base64_decode($password));

        $credentials = [
            'username' => $username,
            'password' => $password,
//            'active' => 1
        ];

        return Auth::guard()->attempt($credentials);
    }

Why aren't the two algorithms output the same string on encryption and base64? I suspect some encoding issues but I can't figure them out. Tried forcing UTF-8 on both but the result is the same.. Any ideas?

Thanks!

EDIT:

Using this base64 library for Java: https://sourceforge.net/projects/iharder/files/base64/2.3/

The default one from Android gives the same results so, yeah.. :/

EDIT 2: First comment suggested checking to see if any party changes the output on concurrent executions and weirdly, yes.. The PHP one.. Why?

This is an output from php artisan tinker

base64_encode($rsa->encrypt('admin'))
=> "T3dBTadyEjvSM96lCwELNzXHNh5bEJtW6QvgdrVT0wZ2KFq8Cs+s7/+IjSrISlNC+ygF+XPhYjEUHa+FSqzgT68KftcVQYL84w8Thbiy6ElLqs7WAbLAaKk10kBqEPNtI0jItOJFXGA07SsQu6g5+OUWfEFShBPg8uSxSYPsjhvATpw6lLCRtVQYqAL1MUwwmaho/ktih5UJgpiCYdwpa0ROiPboKloO0CFOAkR+5rybSLH73p3Fxf1y46qgA3BoPenillkMW8kgv1/bFj1rpRVi2Ca3ioMQt0fOPGchoe3ikz5I6IrrAK0aYhwj3kpoQ2+doLUV+EKXs8iFkA+cjQ=="
>>> base64_encode($rsa->encrypt('admin'))
=> "XJZrhFpw1UsBEC2yKMv0PVQ/H0vvBSXEZEsjQ4vlvjgktifCGAPsac3zwarlV2+TOoNKhn7nCqWer2Gz60UyoHS0xYyNvt/i3Ogsn2ccxhpKRtrB2CEMJOzSdLoUe+4JEObdU1b6SR4ysFbFEjFvo+zWUAfT7i2vM9bdZkwcrL6S2a4bBeWk3t2l91URatggzTOBFtxUB4zHTKyo1SSuR6uqm2q/Jbakj07e64ZZQmWiKY4inDZNgaVVLE+wNq++J4aLwRhSZG4wXuPgNeGHfwgZ3bytlRJUrrNXMXExa1C8eu/js3+WiYFSXPIiTeuQaxsih+suj0abDTFjJygNMA=="
>>> base64_encode($rsa->encrypt('admin'))
=> "DVAFTjZ1Ah6mpN699/PitPj0nLNLhz4zGux9uYLQHmANR/CYEt63+z0vE2xQI9oKE/V4K5a335wvJpz+70hMy6G30cKAwerZ8PudbZgnpGRaF0YlRwzZEQ+XqV5qdQXE6kb4plVZrYrpyHAiPTmO54V+UvCp2YPbNY3Qcr+vbIrn0CZJ7lMwgE9NCGWwiIJF6G6/z4zqc+UbBG9+WUtf16BU8CXhbeU4FOSeuxYr9xbGbjAvtUZXrXpaQPYwgCuWURTWcN2fxmm5fAZuU74rPVMW5slTxTVafcIcUI0bFuMdsx3xj9VIImYhmbM0DTXT/gm66nxSy7aAvj5ckmemfA=="
>>> base64_encode($rsa->encrypt('admin'))
=> "Po8lzluh+ChWdHBxvThrn06kZ1cugTvEvV6UU8JroeM2aYwX4XH9hMSt1U+XmKkmdgxLRXwKUMsYcT7rF7I92tLW6T6fjTED1HoXXWS35okc1zhPTvXFqvMdXq7r4meLrcPmJjfsJsKnso4Ws2aIzHjQxfbPAHQNE2FD1bbOA0aD21MU8HR1qckTFosOP3O8KpxBQW3Z0aTX+k0sy0edwHfHCjQxQ9ne3oWcY+JiKCSFbyWoYxGQML0N11jA5Jik4K3jMA7cDQQzUutWUGN/ABv7OoXYKbfv/3IA8Uqu6jxSgBZjsLb4iUdFtw9QlwOsr4w2flCsPtye0vnDsjOduQ=="
>>> base64_encode($rsa->encrypt('admin'))
=> "rnkB57WUXMw87Hxc6e6MGraGryEQ+3HVwbGEexIGrs4jlqzBHZig7/ykfHzGgZGlrtYGY/FB3Mn6kfkwH1SXVAV6QPdnp0ktxbrqHJmQDDrLxsBlQGbZnSSVglV2EHn9Vm++iiygspv+IRMmOB6XOBxWMcV2AeAGa86EwTj3AKdcOeSPzrIB04G2mH695rEwLHC69KeBZ5vCuPAvVZ5AjhzsutcNEK5WLIcxcFbi1PQb7Amp3mPMpW3g0w+LkU6RkW8GGZ5gPu15PfvT/r8CCDaJbTwCLN2XPAa1R+/x0IZgSM2Tv/qOJBGdkkjGM8/lXeTGW8/oKU85bdlVqEBxdA=="
>>> base64_encode($rsa->encrypt('admin'))
=> "cX+CkQR+t9fdWMo2jHs7FdbmFzcAYkLfhNo6J0O3rAMtg8iR/KoN+RfNA6WQN4DIWMiGsN1F/ipAxiOo8K0V7x7EODgpbw2zGQBL/ueWJyD00UIA0WsXo93ubIXOJ+62dFbz7Ioc9Gtwv3q7HhtmKIh2oDxpffU1uOWzBGE8MW5cYvuWGHRqsgcKxFfiOJht+GkZUS2gdUe7/ke5YsEGLJs4PJzuk/NnPvsKEdlNHoAT+Vyzc3yW9+FtL8OpXDplACFaRS/Urulmvkd5wiy7dhCh9L1QDdgUZshkQ0In2254LFME5tVkpES0ZlD8eLZih84sioTIyeGoUj1gdkHxdw=="
>>> base64_encode($rsa->encrypt('admin'))
=> "JFVZ2dhi6vsLeiXwPDxisxRa+56fCHIM9RORhJ51hgdAr7qeb7O2o0Xx3AVJB/CfX6ZXOFwZ38sATGDpHgEbYT5Tui12IMMLTgLnQnnxyxX8+A5AfYCpAzHOr9Xr41fHdtVDTexcI+77yEakhh57SGhfUQhoTll/k73CDymLkF/DkKw21EY9DXgscffKB5giyC3bd4CiqCZ3j/aa0T70NKtjDT3H5zqrHd3dhqblYRVE7rAbKHYPz6hrv5TUX2rX45er4o53cihGOuzTlwOGDa5f0HGlepnXSvGlgmqCRMbina4LepAlker93HVD56I7rtiRRLqz9BUahkt3GSoZfA=="
>>> 

When encryption is randomized, it provides semantic security . This property doesn't allow a passive observer of ciphertext to determine whether the plaintext behind the observed ciphertext was sent before or not. This is achieved through randomized padding ( PKCS#1 v1.5 padding type 2 or OAEP).

If you want to determine whether your code is compatible, you need to encrypt on one side and decrypt on the other.

It looks like your code should work as-is, depending on what the defaults are. You should always specify your own configuration to prevent the defaults from breaking compatibility when you switch systems.

In Java, you should always provide a fully qualified cipher string:

  • Cipher.getInstance("RSA/ECB/PKCS1Padding"); or
  • Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); (OAEP is preferred nowadays)
  • Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); (OAEP is preferred nowadays)

In phpseclib, you should always change the defaults:

  • $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); or
  • for OAEP with SHA-1:

     $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP); $rsa->setHash("sha1"); $rsa->setMGFHash("sha1"); 
  • for OAEP with SHA-256:

     $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP); $rsa->setHash("sha256"); $rsa->setMGFHash("sha1"); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM