Last active
September 19, 2017 22:38
-
-
Save guilhermesgb/4146c7233193d924acca3ef610319f98 to your computer and use it in GitHub Desktop.
Generating a PagarMe CardHash manually using Java / Android
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.util.Base64; | |
import java.io.IOException; | |
import java.net.URLEncoder; | |
import java.security.InvalidKeyException; | |
import java.security.KeyFactory; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.PublicKey; | |
import java.security.spec.InvalidKeySpecException; | |
import java.security.spec.X509EncodedKeySpec; | |
import javax.crypto.BadPaddingException; | |
import javax.crypto.Cipher; | |
import javax.crypto.IllegalBlockSizeException; | |
import javax.crypto.NoSuchPaddingException; | |
//... | |
Cipher cipher; | |
KeyFactory keyFactory; | |
try { | |
cipher = Cipher.getInstance("RSA/None/PKCS1PADDING"); | |
keyFactory = KeyFactory.getInstance("RSA"); | |
} catch (NoSuchAlgorithmException | NoSuchPaddingException cardHashGenerationImpossible) { | |
//DEVICE (IF ANDROID) OR JAVA ENVIRONMENT UNABLE TO GENERATE CARD HASHES | |
//AS IT WON'T BE ABLE TO PROPERLY ENCRYPT USER CARD INFORMATION. | |
//AS PER https://docs.pagar.me/api/?shell#gerando-card_hash-manualmente, | |
//PAGARME REQUIRES PUBLIC CRYPTOGRAPHY USING RSA W/ PKCS1Padding. | |
} | |
//... | |
//USING RETROFIT TO GET https://api.pagar.me/1/transactions/card_hash_key. | |
Call<JsonObject> fetchPagarMeCardHashPublicKey = AppApi.getInstance() | |
.getPagarMeCardHashPublicKey(Constants.PAGAR_ME_ENCRYPTION_KEY); | |
fetchPagarMeCardHashPublicKey.enqueue(new Callback<JsonObject>() { | |
@Override | |
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) { | |
if (response.isSuccessful() && response.body() != null) { | |
try { | |
JsonObject responseBody = response.body(); | |
int cardHashId = responseBody.get("id").getAsInt(); | |
String rawPublicKey = responseBody.get("public_key").getAsString(); | |
//PAGARME PUBLIC KEYS COME IN PEM FORMAT, SO WE NEED TO CONVERT'EM | |
//TO DER FORMAT SO THAT THEY CAN PLAY NICE WITH X509EncodedKeySpec. | |
rawPublicKey = rawPublicKey | |
.replaceAll("\\s*-----BEGIN PUBLIC KEY-----\\s*", "") | |
.replaceAll("\\s*-----END PUBLIC KEY-----\\s*", "") | |
.replaceAll("\\s", ""); | |
byte[] decodedPublicKey = Base64.decode(rawPublicKey.getBytes("UTF-8"), 0); | |
//SUCCESSFULLY CONVERTED THE PUBLIC KEY TO DER FORMAT. | |
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decodedPublicKey); | |
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); | |
cipher.init(Cipher.ENCRYPT_MODE, publicKey); | |
//NOW FORMATTING CARD INFORMATION IN THE FORMAT EXPECTED BY PAGARME. | |
String cardInformation = String.format(Locale.US, | |
"card_number=%s&card_holder_name=%s&card_expiration_date=%s" | |
+ "&card_cvv=%s", creditCardNumber.replace(" ", "").trim(), | |
URLEncoder.encode(profileCreditCardName.getText().trim(), "UTF-8").replace("+", "%20"), | |
creditCardGoodThru.replace("/", "").trim(), profileCreditCardCvc.getText().trim()); | |
//THEN WE USE OUR CIPHER TO ENCRYPT AND THEN BASE64-ENCODE THE CARD INFORMATION, | |
//AND FINALLY, APPEND THE ASSIGNED CARD ID AS PREFIX OF THE RESULT TO COMPOSE THE CARD HASH. | |
byte[] encryptedCardInformation = cipher.doFinal(cardInformation.getBytes("UTF-8")); | |
String cardHash = String.format(Locale.US, "%d_%s", cardHashId, | |
(Base64.encodeToString(encryptedCardInformation, Base64.DEFAULT))) | |
.replaceAll("\\s", ""); | |
//NOW YOU MIGHT WANT TO SEND THE CARD HASH TO YOUR BACKEND SERVER. | |
} catch (InvalidKeySpecException | InvalidKeyException invalidKey) { | |
//PROBLEMS WITH THE PUBLIC KEY RECEIVED FROM PAGARME. | |
} catch (BadPaddingException | IllegalBlockSizeException | IOException encryptionException) { | |
//I/O ERRORS HAPPENED WHILE TRYING TO ENCRYPT CARD INFORMATION. | |
} | |
} else { | |
//PAGARME PROBABLY DIDN'T LIKE THE PAGAR_ME_ENCRYPTION_KEY YOU USED IN THE GET REQUEST... | |
} | |
} | |
@Override | |
public void onFailure(Call<JsonObject> call, Throwable throwable) { | |
//COULD NOT RECEIVE PUBLIC KEY FROM PAGARME. | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment