EXPLOREAPI

Logo Explore - Data for success

Deprecated authentication methods

IP address restriction

Authentication to EXPLORE API used to work through an authentication key (CleClient) and IP address restrictions. You then had to add the “CleClient” parameter in the URI (or in the body in case of an HTTP POST request). The list of IP addresses which should be authorized have to be communicated to our technical support team.

URI Encryption

When IP restriction is out of the question, an encryption system can be used in its stead. All EXPLORE API generic webservices can be called in this encrypted way, which we call “signed”.

You only need two parameters then:

The “Signature” parameter is encrypted via a method based on a reliable algorithm; AES (Advanced Encryption Standard). If you want more information on AES, you can go check this page.

Your team and EXPLORE will then share a secret key that wil allow for decryption and thus secure your call. No one, without this key, will be able to reveal what the encrypted parameter contains.

The URI you get after encryption, for security reasons, only works the same day it has been generated. To implement this, you have to add the date to your secret key as is demonstrated below (in C#):

string cipherKey = DateTime.Today.ToString("yyyyMMdd") + secretKey;

The content of the “Signature” parameter corresponds to the “normal” query string of the parameter. Thus, if you want to send a request to the Amenagement webservice in the Opportunites section, the string you will have to encrypt will look like “CleClient=[your authentication key]&DateDebut=[yyyy-MM-dd]&DateFin=[yyyy-MM-dd]”.

Encryption methods

The “Signature” string can be encrypted using the following methods:

            
public static string Encrypt(string toEncrypt, string cKey)
{
    byte[] plainText = Encoding.UTF8.GetBytes(toEncrypt);

    Rfc2898DeriveBytes rfcDb = new(cKey, Encoding.UTF8.GetBytes(cKey));
    byte[] key = rfcDb.GetBytes(16);
    byte[] iv = rfcDb.GetBytes(16);

    Aes? aes = Aes.Create("AesManaged");

    if (aes == null)
        throw new NotImplementedException();

    ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);
    byte[]? cipherBytes = null;

    using (MemoryStream ms = new())
    {
        using CryptoStream cs = new(ms, encryptor, CryptoStreamMode.Write);
        cs.Write(plainText, 0, plainText.Length);
        cs.FlushFinalBlock();

        cipherBytes = ms.ToArray();
    }

    return Convert.ToBase64String(cipherBytes).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static string Encrypt(string toEncrypt, string ckey)
{
    byte[] plainText = Encoding.UTF8.GetBytes(toEncrypt);

    Rfc2898DeriveBytes rfcDb = new Rfc2898DeriveBytes(ckey, Encoding.UTF8.GetBytes(ckey));
    byte[] key = rfcDb.GetBytes(16);
    byte[] iv = rfcDb.GetBytes(16);

    RijndaelManaged rijndael = new RijndaelManaged
    {
        Mode = CipherMode.CBC;
    };

    ICryptoTransform encryptor = rijndael.CreateEncryptor(key, iv);
    byte[] cipherBytes = null;

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write));
        {
            cs.Write(plainText, 0, plainText.Length);
            cs.FlushFinalBlock();

            cipherBytes = ms.ToArray();
        }
    }

    return Convert.ToBase64String(cipherBytes).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static string Encrypt(string toEncrypt, string cKey)
{
    byte[] encrypted = null;

    using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
    {
        char[] keyChars = cKey.ToCharArray();
        byte[] key = new byte[16];
        byte[] iv = new byte[16];

        for (int i = 0; i < 16; i++)
        key[i] = (byte)key[i];

        for (int i = 16; i < 32; i++)
        iv[i - 16] = (byte)key[i];

        aes.Key = key;
        aes.IV = iv;
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.PKCS7;

        ICryptoTransform enc = aes.CreateEncryptor(aes.Key, aes.IV);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write))
            {
                using (StreamWriter sw = new StreamWriter(cs))
                {
                    sw.Write(toEncrypt);
                }

                encrypted = ms.ToArray();
            }
        }
    }

    return Convert.ToBase64String(encrpted).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static String encrypt(String toEncrypt, String cKey) throws Exception
{
    try
    {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec pbeKeySpec = new PBEKeySpec(cKey.toCharArray(), Arrays.copyOf(cKey.getBytes("UTF-8"), cKey.getBytes("UTF-8").length), 1000, 384);
        byte[] secretKeyBytes = factory.generateSecret(pbeKeySpec).getEncoded();

        IvParameterSpec ivSpec = new IvParameterSpec(Arrays.copyOfRange(secretKeyBytes, 16, 32));
        SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secretKeyBytes, 0, 16), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);

        byte[] encrypted = cipher.doFinal(toEncrypt.getBytes("UTF-8"));

        return Base64.getEncoder().encodeToString(encrypted).replace("+", "-").replace("/", "_");
    }
        catch (Exception ex)
    {
        throw ex;
    }
}
            
        
            
<?php

function Encrypt($toEncrypt, $cKey)
{
    require 'PBKDF2.class.php';
    $pbkdf = new PBKDF2();
    $rfcdb = $pbkdf->hash("sha1", $cKey, $cKey, 1000, 32, true);

    $key = substr($rfcdb, 0, 16);
    $iv = substr($rfcdb, 16, 16);

    $cipherTextRaw = openssl_encrypt($toEncrypt, "AES-128-CBC", $key, 1, $iv);
    $cipherTextBase64 = str_replace(array("+", "/"), array("-", "_"), base64_encode($cipherTextRaw));

    return $cipherTextBase64;
}

?>
            
        
            
<?php

function Encrypt($toEncrypt, $cKey)
{
    $rfcdb = hash_pbkdf2("sha1", $cKey, $cKey, 1000, 32, true);

    $key = substr($rfcdb, 0, 16);
    $iv = substr($rfcdb, 16, 16);

    $cipherTextRaw = openssl_encrypt($toEncrypt, "AES-128-CBC", $key, 1, $iv);
    $cipherTextBase64 = str_replace(array("+", "/"), array("-", "_"), base64_encode($cipherTextRaw));

    return $cipherTextBase64;
}

?>
            
        
            
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def encrypt(to_encrypt, cKey):
    padded = pad(to_encrypt.encode('utf-8'), AES.block_size)

    salt = cKey.encode('utf-8')
    key = hashlib.pbkdf2_hmac('sha1', cKey.encode('utf-8'), salt, 1000, dklen=32)
    iv = key[16:32]
    key = key[:16]
    
    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(padded)
    
    encoded = base64.urlsafe_b64encode(encrypted).decode().replace("+", "-").replace("/", "_")
    return encoded
            
        
            

DateTime startDate = DateTime.Today.AddDays(-6);
DateTime endDate = DateTime.Today;
string cipherKey = DateTime.Today.ToString("yyyyMMdd") + secretKey;
string parameters = string.Concat("CleClient=", authenticationKey, "&DateDebut=", startDate.ToString("yyyy-MM-dd"), "&DateFin=", endDate.ToString("yyyy-MM-dd"));
string signature = Encrypt(parameters, cipherKey);
string endpoint = "https://extranet.explore.fr/ExploreAPI/api/Opportunites/MarchesPublics?CleClient=" + authenticationKey + "&Signature=" + signature;