从java到python的API调用移植(Kostal Plenticore)

从java到python的API调用移植(Kostal Plenticore),java,python,api,Java,Python,Api,我试图通过api从我的逆变器中读取传感器数据。(Kostal PLENTICORE plus) 由于缺少Kostal的文档,我无法让它工作。身份验证是这里的大问题。但是我刚刚从Openhab找到了代码。 现在我正在尝试将它尽可能简单地移植到python中。 我现在的代码: 导入请求 随机输入 导入字符串 导入json 导入hashlib 进口hmac 导入hashlib 导入binascii def随机字符串(stringLength=10): “”“生成固定长度的随机字符串”“” 字母=字符


我试图通过api从我的逆变器中读取传感器数据。(Kostal PLENTICORE plus) 由于缺少Kostal的文档,我无法让它工作。身份验证是这里的大问题。但是我刚刚从Openhab找到了代码。

现在我正在尝试将它尽可能简单地移植到python中。
我现在的代码:

导入请求
随机输入
导入字符串
导入json
导入hashlib
进口hmac
导入hashlib
导入binascii
def随机字符串(stringLength=10):
“”“生成固定长度的随机字符串”“”
字母=字符串。ascii_小写
返回“”。在范围(stringLength)内为i连接(随机选择(字母))
def GETPKDF2HASH(密码、salt、轮数):
key=hashlib.pbkdf2_hmac(
“sha256”,#HMAC的哈希摘要算法
密码。编码('utf-8'),#将密码转换为字节
盐,提供盐
轮数#建议至少使用100000次SHA-256迭代
)
返回键
def create_sha256_签名(字节密钥,消息):
#byte_key=binascii.unhexlify(key)
message=message.encode()
返回hmac.new(byte_key,message,hashlib.sha256).hexdigest().upper()
def createClientProof(客户端签名、服务器签名):
clientlength=len(clientSignature.encode('utf-8'))
结果=[]
#对于范围内的i(clientlength):
#结果[i]=(0xff&(字节(客户端签名[i])^字节(服务器签名[i]))
返回结果**
用户名=“用户”
password=“A123456789”
url='1〕http://192.168.1.23/api/v1/'
clientNonce=randomString(16)
reqstart={“用户名”:用户名,“nonce”:clientNonce}
a=requests.post(url+'auth/start',json=reqstart)
anserstart=json.loads(a.text)
serverNonce=anserstart['nonce']
transactionId=anserstart['transactionId']
salt=anserstart['salt']
rounds=anserstart['rounds']
saltedpassword=getPBKDF2Hash(密码、salt、轮数)
clientkey=create_sha256_签名(saltedpassword,“客户端密钥”)
serverkey=创建\u sha256\u签名(saltedpassword,“服务器密钥”)
storedKey=hashlib.sha256(clientkey.hexdigest())
authMessage=“n={},r={},r={},s={},i={},c=biw,r={}”
格式(用户名、clientNonce、serverNonce、salt、rounds、serverNonce)
clientSignature=create_sha256_签名(storedKey,authMessage)
serverSignature=创建\u sha256\u签名(storedKey,serverkey)
打印(anserstart)
#打印(saltedpassword)
#打印(clientkey)
#打印(服务器密钥)
#打印(storedKey)
打印(客户签名)
打印(服务器签名)
打印(createClientProof(客户端签名、服务器签名))
#reqfinish={“证明”:“”“transactionId”:transactionId}
#b=requests.post(url+'auth/start',json=reqfinish)
#answerfinish=json.loads(b.text)
#打印(回答完成)

现在回答我的问题: 我坚持创建客户机证明(函数createClientProof)。有人能帮我像在java中那样做XOR吗? 除此之外,我对加密或这种身份验证没有太多经验。有人能告诉我我所做的工作是否正确吗

原名:

/**
 * This method generates the HMACSha256 encrypted value of the given value
 *
 * @param password       Password used for encryption
 * @param valueToEncrypt value to encrypt
 * @return encrypted value
 * @throws InvalidKeyException      thrown if the key generated from the password is invalid
 * @throws NoSuchAlgorithmException thrown if HMAC SHA 256 is not supported
 */
static byte[] getHMACSha256(byte[] password, String valueToEncrypt)
        throws InvalidKeyException, NoSuchAlgorithmException {
    SecretKeySpec signingKey = new SecretKeySpec(password, HMAC_SHA256_ALGORITHM);
    Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
    mac.init(signingKey);
    mac.update(valueToEncrypt.getBytes());
    return mac.doFinal();
}

/**
 * This methods generates the client proof.
 * It is calculated as XOR between the {@link clientSignature} and the {@link serverSignature}
 *
 * @param clientSignature client signature
 * @param serverSignature server signature
 * @return client proof
 */
static String createClientProof(byte[] clientSignature, byte[] serverSignature) {
    byte[] result = new byte[clientSignature.length];
    for (int i = 0; i < clientSignature.length; i++) {
        result[i] = (byte) (0xff & (clientSignature[i] ^ serverSignature[i]));
    }
    return Base64.getEncoder().encodeToString(result);
}

/**
 * Create the PBKDF2 hash
 *
 * @param password password
 * @param salt     salt
 * @param rounds   rounds
 * @return hash
 * @throws NoSuchAlgorithmException if PBKDF2WithHmacSHA256 is not supported
 * @throws InvalidKeySpecException  if the key specification is not supported
 */
static byte[] getPBKDF2Hash(String password, byte[] salt, int rounds)
        throws NoSuchAlgorithmException, InvalidKeySpecException {
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, rounds, 256);
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    return skf.generateSecret(spec).getEncoded();
}

/**
 * Create the SHA256 hash value for the given byte array
 *
 * @param valueToHash byte array to get the hash value for
 * @return the hash value
 * @throws NoSuchAlgorithmException if SHA256 is not supported
 */
static byte[] getSha256Hash(byte[] valueToHash) throws NoSuchAlgorithmException {
    return MessageDigest.getInstance(SHA_256_HASH).digest(valueToHash);
}
/**
*此方法生成给定值的HMACSha256加密值
*
*@param password用于加密的密码
*@param valueToEncrypt要加密的值
*@返回加密值
*@throws InvalidKeyException在密码生成的密钥无效时引发
*@throws nosuchalgorithException在不支持HMAC SHA 256时引发
*/
静态字节[]getHMACSha256(字节[]密码,字符串值加密)
抛出InvalidKeyException,NoSuchAlgorithmException{
SecretKeySpec signingKey=新SecretKeySpec(密码,HMAC_SHA256_算法);
Mac Mac=Mac.getInstance(HMAC_SHA256_算法);
mac.init(签名密钥);
mac.update(valueToEncrypt.getBytes());
返回mac.doFinal();
}
/**
*此方法生成客户机证明。
*它被计算为{@link clientSignature}和{@link serverSignature}之间的异或
*
*@param clientSignature客户端签名
*@param serverSignature服务器签名
*@返回客户证明
*/
静态字符串createClientProof(字节[]clientSignature,字节[]serverSignature){
字节[]结果=新字节[clientSignature.length];
for(int i=0;i

感谢您的帮助

我刚刚编写了一些python代码来连接逆变器。工作到目前为止,您可以看到如何处理XOR操作。 现在/auth/start和/auth/finish已经完成。下一步是/auth/create_会话,它还需要一些加密操作。如果你
import random
import string
import base64
import json
import requests
import hashlib
import os
import hmac

USER_TYPE = "user"
PASSWD = 'yourSecretPassword'
BASE_URL = "http://xxx.xxx.xxx.xxx/api/v1"
AUTH_START = "/auth/start"
AUTH_FINISH = "/auth/finish"
AUTH_CREATE_SESSION = "/auth/create_session"

def randomString(stringLength):
    letters = string.ascii_letters
    return ''.join(random.choice(letters) for i in range(stringLength))

u = randomString(12)
u = base64.b64encode(u.encode('utf-8')).decode('utf-8')

step1 = {
  "username": USER_TYPE,
  "nonce": u
}
step1 = json.dumps(step1)

url = BASE_URL + AUTH_START
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step1, headers=headers)
response = json.loads(response.text)
i = response['nonce']
e = response['transactionId']
o = response['rounds']
a = response['salt']
bitSalt = base64.b64decode(a)

def getPBKDF2Hash(password, bytedSalt, rounds):
    return hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), bytedSalt, rounds)

r = getPBKDF2Hash(PASSWD,bitSalt,o)
s = hmac.new(r, "Client Key".encode('utf-8'), hashlib.sha256).digest()
c = hmac.new(r, "Server Key".encode('utf-8'), hashlib.sha256).digest()
_ = hashlib.sha256(s).digest()
d = "n=user,r="+u+",r="+i+",s="+a+",i="+str(o)+",c=biws,r="+i
g = hmac.new(_, d.encode('utf-8'), hashlib.sha256).digest()
p = hmac.new(c, d.encode('utf-8'), hashlib.sha256).digest()
f = bytes(a ^ b for (a, b) in zip(s, g))
proof = base64.b64encode(f).decode('utf-8')

step2 = {
  "transactionId": e,
  "proof": proof
}
step2 = json.dumps(step2)

url = BASE_URL + AUTH_FINISH
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step2, headers=headers)
response = json.loads(response.text)
token = response['token']
signature = response['signature']

# TODO more encryption stuff 
import sys
import random
import string
import base64
import json
import requests
import hashlib
import os
import hmac
from Crypto.Cipher import AES
import binascii
# pip install pycryptodome

USER_TYPE = "user"
PASSWD = 'yourSecretPassword'
BASE_URL = "http://xxx.xxx.xxx.xxx/api/v1"
AUTH_START = "/auth/start"
AUTH_FINISH = "/auth/finish"
AUTH_CREATE_SESSION = "/auth/create_session"
ME = "/auth/me"

def randomString(stringLength):
    letters = string.ascii_letters
    return ''.join(random.choice(letters) for i in range(stringLength))

u = randomString(12)
u = base64.b64encode(u.encode('utf-8')).decode('utf-8')

step1 = {
  "username": USER_TYPE,
  "nonce": u
}
step1 = json.dumps(step1)

url = BASE_URL + AUTH_START
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step1, headers=headers)
response = json.loads(response.text)
i = response['nonce']
e = response['transactionId']
o = response['rounds']
a = response['salt']
bitSalt = base64.b64decode(a)

def getPBKDF2Hash(password, bytedSalt, rounds):
    return hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), bytedSalt, rounds)

r = getPBKDF2Hash(PASSWD,bitSalt,o)
s = hmac.new(r, "Client Key".encode('utf-8'), hashlib.sha256).digest()
c = hmac.new(r, "Server Key".encode('utf-8'), hashlib.sha256).digest()
_ = hashlib.sha256(s).digest()
d = "n=user,r="+u+",r="+i+",s="+a+",i="+str(o)+",c=biws,r="+i
g = hmac.new(_, d.encode('utf-8'), hashlib.sha256).digest()
p = hmac.new(c, d.encode('utf-8'), hashlib.sha256).digest()
f = bytes(a ^ b for (a, b) in zip(s, g))
proof = base64.b64encode(f).decode('utf-8')

step2 = {
  "transactionId": e,
  "proof": proof
}
step2 = json.dumps(step2)

url = BASE_URL + AUTH_FINISH
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
response = requests.post(url, data=step2, headers=headers)
response = json.loads(response.text)
token = response['token']
signature = response['signature']

y = hmac.new(_, "Session Key".encode('utf-8'), hashlib.sha256)
y.update(d.encode('utf-8'))
y.update(s)
P = y.digest()
protocol_key = P
t = os.urandom(16)

e2 = AES.new(protocol_key,AES.MODE_GCM,t)
e2, authtag = e2.encrypt_and_digest(token.encode('utf-8'))

step3 = {
  "transactionId": e,
  "iv": base64.b64encode(t).decode('utf-8'),
  "tag": base64.b64encode(authtag).decode("utf-8"),
  "payload": base64.b64encode(e2).decode('utf-8')
}
step3 = json.dumps(step3)

headers = { 'Content-type': 'application/json', 'Accept': 'application/json' }
url = BASE_URL + AUTH_CREATE_SESSION
response = requests.post(url, data=step3, headers=headers)
response = json.loads(response.text)
sessionId = response['sessionId']

#create a new header with the new Session-ID for all further requests
headers = { 'Content-type': 'application/json', 'Accept': 'application/json', 'authorization': "Session " + sessionId }
url = BASE_URL + ME
response = requests.get(url = url, headers = headers)
response = json.loads(response.text)
authOK = response['authenticated']
if not authOK:
    print("authorization NOT OK")
    sys.exit()

url = BASE_URL + "/info/version"
response = requests.get(url = url, headers = headers)
response = json.loads(response.text)
swversion = response['sw_version']
apiversion = response['api_version']
hostname = response['hostname']
name = response['name']
print("Connected to the inverter " + name + "/" + hostname + " with SW-Version " + swversion + " and API-Version " + apiversion)

# Auth OK, now send your desired requests