Data Import API
Authentication
Authentication is implemented by signing a request using ECDSA algorithm.
Generate Private and Public Keys
Your private key is used to sign your authentication requests. Run this command to create your private key:
openssl ecparam -name prime256v1 -genkey -out private.pem
Use private key to generate a public key:
openssl ec -in private.pem -pubout -out public.pem
The result of these commands will be two files:
private.pem example
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICANhwl1a8C7PDQE+BBBY1nr6RPIBxcp461EyBU7k5WzoAoGCCqGSM49
AwEHoUQDQgAEdVgfFzlM6jT2okGwtM65Cl091OUTA7+bTj2nRmyIsU33TQeq15pn
hTz7nk3rJK+p/hCsk/mHdEAMGsb/4cKqkA==
-----END EC PRIVATE KEY-----
You should leave only this part:
MHcCAQEEICANhwl1a8C7PDQE+BBBY1nr6RPIBxcp461EyBU7k5WzoAoGCCqGSM49
AwEHoUQDQgAEdVgfFzlM6jT2okGwtM65Cl091OUTA7+bTj2nRmyIsU33TQeq15pn
hTz7nk3rJK+p/hCsk/mHdEAMGsb/4cKqkA==
public.pem example
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdVgfFzlM6jT2okGwtM65Cl091OUT
A7+bTj2nRmyIsU33TQeq15pnhTz7nk3rJK+p/hCsk/mHdEAMGsb/4cKqkA==
-----END PUBLIC KEY-----
For authentication use Authorization Header like:
Authorization: s1mpl signature <identity> <alg> <data>
- identity - user/service (provided be vendor)
- alg - signature algorithm (for project es256)
- data - byte array of signature data (base64):
- timestamp - 8 bytes, UTC time of sending the HTTP request
- request id - 16 bytes, request's GUID, new for each request
- signature - remaining bytes (the number depends on the algorithm), a digital signature of the previous bytes
Signing examples
- C#
- Java
private static readonly byte[] PrivateKey = Convert.FromBase64String(@"MHcCAQEEICANhwl1a8C7PDQE+BBBY1nr6RPIBxcp461EyBU7k5WzoAoGCCqGSM49AwEHoUQDQgAEdVgfFzlM6jT2okGwtM65Cl091OUTA7+bTj2nRmyIsU33TQeq15pnhTz7nk3rJK+p/hCsk/mHdEAMGsb/4cKqkA==");
private static async Task Main(string[] args)
{
var client = new HttpClient();
var url = string.Format(BaseUrl, "queue?take=100");
var request = new HttpRequestMessage(HttpMethod.Get, url);
var sign = CreateSignature();
request.Headers.Add("Authorization", $"s1mpl signature some-service es256 { Convert.ToBase64String(sign) }");
var response = await client.SendAsync(request);
Console.ReadLine();
}
private static byte[] CreateSignature()
{
var alg = ECDsa.Create();
if (alg == null)
throw new InvalidOperationException("No signature algorithm implementation available");
var signingData = BitConverter.GetBytes(DateTime.UtcNow.Ticks)
.Concat(Guid.NewGuid().ToByteArray())
.ToArray();
alg.ImportECPrivateKey(PrivateKey, out _);
var signature = alg.SignData(signingData, HashAlgorithmName.SHA256);
return signingData.Concat(signature).ToArray();
}
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.Signature;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
class SignatureExample {
private static final String PRIVATE_KEY = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKkbwfsFlS8hCFBLS1SzXNyrOy8zOzjvMPO1a4GX4+SChRANCAARvAkGTfrfVrJ5/r9KmP4/Scl05zBYev0pyKO8Yn//MQuoGqr4Phz5sHROJo6ckbdCqQA+NFUwvw+11NMQBxLFh";
public static void main(String[] args) throws Exception {
var encoded = Base64.getDecoder().decode(PRIVATE_KEY);
var keyFactory = KeyFactory.getInstance("EC");
var keySpec = new PKCS8EncodedKeySpec(encoded);
var privateKey = keyFactory.generatePrivate(keySpec);
var signature = createSignature(privateKey);
var request = HttpRequest.newBuilder()
.uri(new URI("https://some-api.s1mpl.com/some-endpoint"))
.header("Authorization", "s1mpl signature some-identity es256 " + signature)
.GET()
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.setOut(new PrintStream(new FileOutputStream("out.txt"), true, "UTF-8"));
System.out.println(response);
System.out.println(response.body());
}
private static String createSignature(PrivateKey privateKey) throws Exception {
var uuid = UUID.randomUUID();
var ticks = getTicks();
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * 3);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putLong(ticks);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
var signingData = buffer.array();
var ecdsa = Signature.getInstance("SHA256withECDSAinP1363format");
ecdsa.initSign(privateKey);
ecdsa.update(signingData);
var signature = ecdsa.sign();
var result = new byte[signingData.length + signature.length];
System.arraycopy(signingData, 0, result, 0, signingData.length);
System.arraycopy(signature, 0, result, signingData.length, signature.length);
return Base64.getEncoder().encodeToString(result);
}
private static long getTicks() {
final long TICKS_AT_EPOCH = 621355968000000000L;
final long TICKS_PER_MS = 10000;
return System.currentTimeMillis() * TICKS_PER_MS + TICKS_AT_EPOCH;
}
}