If you send an HTTP request to OceanBase Shell (OBShell), OBShell authenticates your identify to protect the data transmission from replay attacks.
Procedure
Step 1: Generate a ciphertext string.
- Obtain the public key of the target agent by calling the
/api/v1/secretAPI. - Generate a JSON string in the format of { "password": ${plaintext password}, "ts": ${expiration timestamp} }.
- Encrypt the JSON string by using the public key based on the RSA algorithm to generate a byte sequence.
- Convert the byte sequence into a Base64-encoded ciphertext string.
- Obtain the public key of the target agent by calling the
Step 2: Send an HTTP request that contains the ciphertext string. Make sure that you specify the
X-OCS-Authfield in the header of the request, so that OBShell can authenticate the request.
X-OCS-Auth: {ciphertext}.
After receiving the request, OBShell parses the password of the root user of the sys tenant and verifies the password. If the verification succeeds, OBShell continues to process the request. Otherwise, an error is returned. Only the HTTP header can contain authentication strings.
Sample code for ciphertext generation in Python
import requests as req
import json
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
import base64
import time
def encrypt(s, pk):
key = RSA.import_key(base64.b64decode(pk))
cipher = PKCS1_cipher.new(key)
return base64.b64encode(cipher.encrypt(bytes(s.encode('utf8')))).decode('utf8')
def auth(pwd, pk):
auth_json = json.dumps({'password': pwd, 'ts': int(time.time()) + 5})
return encrypt(auth_json, pk)
resp = req.get('http://xxx.xxx.1:2886/api/v1/secret').text
resp = json.loads(resp)
pk = resp['data']['public_key']
pwd = '1111'
print(auth(pwd, pk))
Sample code for ciphertext generation in Go
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// RSAEncrypt function encrypts a byte array using the provided public key
func RSAEncrypt(raw []byte, pk string) (string, error) {
pkix, err := base64.StdEncoding.DecodeString(pk)
if err != nil {
return "", err
}
pub, err := x509.ParsePKCS1PublicKey(pkix)
if err != nil {
return "", err
}
b, err := rsa.EncryptPKCS1v15(rand.Reader, pub, raw)
return base64.StdEncoding.EncodeToString(b), err
}
// getPublicKey function retrieves the public key from the API
func getPublicKey(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var response struct {
Data struct {
PublicKey string `json:"public_key"`
} `json:"data"`
}
if err = json.Unmarshal(body, &response); err != nil {
return "", err
}
return response.Data.PublicKey, nil
}
// auth function creates an authentication JSON object and encrypts it
func auth(pwd string, pk string) (string, error) {
authMap := map[string]interface{}{
"password": pwd,
"ts": time.Now().Unix() + 5,
}
authJSON, err := json.Marshal(authMap)
if err != nil {
return "", err
}
return RSAEncrypt(authJSON, pk)
}
func genAuth() (err error) {
publicKey, err := getPublicKey("http://xxx.xxx.1:2886/api/v1/secret")
if err != nil {
return
}
// Authenticate using the password and public key
encryptedAuth, err := auth("1111", publicKey)
if err != nil {
return
}
fmt.Println(encryptedAuth)
return nil
}
func main() {
if err := genAuth(); err != nil {
fmt.Println("err: ", err)
}
}
Sample code for ciphertext generation in Java
package com.oceanbase.vos
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.crypto.Cipher;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class Main {
public static void main(String[] args) {
try {
// Obtains the public key.
String pkcs1PublicKeyStr = getPublicKey("http://xxx.xxx.1:2886/api/v1/secret");
String password = "1111";
long timestamp = System.currentTimeMillis() / 1000 + 100000;
PublicKey publicKey = convertPKCS1ToPublicKey(pkcs1PublicKeyStr);
String encryptedPassword = encryptPasswordWithRSA(password, timestamp, publicKey);
System.out.println(encryptedPassword);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getPublicKey(String urlStr) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
JSONObject jsonResponse = JSON.parseObject(response.toString());
return jsonResponse.getJSONObject("data").getString("public_key");
}
} else {
throw new Exception("HTTP request failed with code " + responseCode);
}
}
private static PublicKey convertPKCS1ToPublicKey(String pkcs1PublicKeyStr) throws Exception {
pkcs1PublicKeyStr = pkcs1PublicKeyStr.replaceAll("\\n", "")
.replace("-----BEGIN RSA PUBLIC KEY-----", "")
.replace("-----END RSA PUBLIC KEY-----", "");
byte[] pkcs1PublicKey = Base64.getDecoder().decode(pkcs1PublicKeyStr);
ASN1InputStream asn1InputStream = new ASN1InputStream(pkcs1PublicKey);
ASN1Sequence sequence = (ASN1Sequence) asn1InputStream.readObject();
BigInteger modulus = ((ASN1Integer) sequence.getObjectAt(0)).getValue();
BigInteger publicExponent = ((ASN1Integer) sequence.getObjectAt(1)).getValue();
asn1InputStream.close();
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(publicKeySpec);
}
private static String encryptPasswordWithRSA(String password, long timestamp, PublicKey publicKey) throws Exception {
JSONObject json = new JSONObject();
json.put("password", password);
json.put("ts", timestamp);
String jsonString = json.toString();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(jsonString.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
}