Skip to content

Instantly share code, notes, and snippets.

@oded-regev
Created November 2, 2020 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oded-regev/01a9c2b120204feb47cca5a9e5644192 to your computer and use it in GitHub Desktop.
Save oded-regev/01a9c2b120204feb47cca5a9e5644192 to your computer and use it in GitHub Desktop.
Prepare the Signature for SkAdNetwork iOS14
package main.java.com.abccompany.example;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.regex.Pattern;
public class SignaturePoc {
public static void main(String[] args) throws Exception {
final String AdNetworkVersion = "2.0";
final String AdNetworkIdentifier = "97r2b46746.skadnetwork"; // ABC AdNetwork ID on Apple
final String AdNetworkCampaignIdentifier = "99";
final String ITunesItemIdentifier = "711455226"; // Forge of Empires App Store Page
final String AdNetworkNonce = "e7b315b5-5d3d-4ceb-bb90-b617dee5e173";
final String SourceAppStoreIdentifier = "331786748"; // CNN App Store page
final String ParameterAdNetworkTimestamp = "1598441577"; // The Current Unix Timestamp
final String prepareSignatureForV1 = AdNetworkIdentifier + '\u2063' + AdNetworkCampaignIdentifier + '\u2063' + ITunesItemIdentifier + '\u2063' + AdNetworkNonce + '\u2063' + ParameterAdNetworkTimestamp;
final String prepareSignatureForV2 = AdNetworkVersion + '\u2063' + AdNetworkIdentifier + '\u2063' + AdNetworkCampaignIdentifier + '\u2063' + ITunesItemIdentifier + '\u2063' + AdNetworkNonce + '\u2063' + SourceAppStoreIdentifier + '\u2063' + ParameterAdNetworkTimestamp;
System.out.println("--- Version 1.0 ---");
signStringMessage(prepareSignatureForV1);
System.out.println("\n\n--- Version 1.0 ---");
signStringMessage(prepareSignatureForV2);
}
static private String signStringMessage(String msg) throws Exception {
System.out.println("signStringMessage: " + msg);
final String ALGO = "SHA256withECDSA";
KeyFactory kf = KeyFactory.getInstance("EC");
byte[] keyBytesArray = loadPEM("file.pem");
PKCS8EncodedKeySpec pkcs8EncodedKey = new PKCS8EncodedKeySpec(keyBytesArray);
PrivateKey key = kf.generatePrivate(pkcs8EncodedKey);
/*
* Create a Signature object and initialize it with the private key
*/
Signature ecdsa = Signature.getInstance(ALGO);
ecdsa.initSign(key);
byte[] strByte = msg.getBytes("UTF-8");
ecdsa.update(strByte);
/*
* Now that all the data to be signed has been read in, generate a
* signature for it
*/
byte[] realSig = ecdsa.sign();
// https://developer.apple.com/documentation/storekit/skadnetwork/generating_the_signature_to_validate_an_installation#3627357
// Encode the binary signature you generated into a Base64 string.
String sig = Base64.getEncoder().encodeToString(realSig);
System.out.println("Signature: " + sig);
return sig;
}
static private byte[] loadPEM(String fileName) throws IOException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream in = classloader.getResourceAsStream(fileName);
String pem = new String(readAllBytes(in), StandardCharsets.ISO_8859_1);
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pem).replaceFirst("$1");
return Base64.getMimeDecoder().decode(encoded);
}
static byte[] readAllBytes(InputStream in) throws IOException {
ByteArrayOutputStream baos= new ByteArrayOutputStream();
byte[] buf = new byte[1024];
for (int read=0; read != -1; read = in.read(buf)) { baos.write(buf, 0, read); }
return baos.toByteArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment