2016-04-21 11 views
1

Я разрабатываю инфраструктуру P2P, которая будет иметь данные из набора различных приложений, распространяемых по сети. Это наложение P2P состоит из набора витых серверов Python.Использование веб-Crypto API JWK в Python

Мне нужно гарантировать безопасность и конфиденциальность сохраненных данных для каждого пользователя каждого приложения. Следовательно, я создаю пары ключей RSA на клиентской стороне веб-приложения, используя Web Crypto API. Пара ключей RSA также будет сохранена в наложении P2P. Итак, я шифрую на стороне клиента, закрытые ключи с выводом пароля пользователя.

Кроме того, я использую модуль jwk to pem для преобразования открытого ключа JWK в ключ PEM, который будет использоваться в библиотеке криптографии Python (PyCrypt или m2Crypto).

Наконец, я должен гарантировать, что сообщение, содержащее эти учетные данные, а также данные пользователя, сохраняет свою целостность. Поэтому на стороне клиента я подписываю эти данные с помощью личного ключа пользователя.

Я отправляю данные, а также подпись, как в массиве ArrayBuffer, на сервер, закодированные в base64.

function signData(private_key, data, callback){ 

    var dataForHash = str2ab(JSON.stringify(sortObject(data))); 
    computeSHA(dataForHash, "SHA-256", function(hash){ 


     signRSA(private_key, hash, function(data){  
      callback(data.buffer.b64encode(), dataForHash.b64encode()); 
     });  
    }); 
} 

function computeSHA(data, mode, callback){ 
    window.crypto.subtle.digest(
     { 
      name: mode, 
     }, 
     data 
    ) 
    .then(function(hash){ 
     callback(new Uint8Array(hash).buffer); 
    }) 
    .catch(function(err){ 
     console.error(err); 
    }); 
} 

function signRSA(private_key, data, callback){ 
    window.crypto.subtle.sign(
     { 
      name: "RSASSA-PKCS1-v1_5", 
     }, 
     private_key, 
     data 
    ) 
    .then(function(signature){ 
     callback(new Uint8Array(signature)); 
    }) 
    .catch(function(err){ 
     console.error(err); 
    }); 
} 

ArrayBuffer.prototype.b64encode = function(){ 
    return btoa(String.fromCharCode.apply(null, new Uint8Array(this))); 
}; 

Впоследствии, когда сервер Python получает этот HTTP-запрос, он декодирует данные и подпись из base64.

dataForHash = base64.b64decode(dataReceived['data']) 
signature = base64.b64decode(dataReceived['signature']) 

Для проверки подписи необходим открытый ключ. Следовательно:

data = utils.byteify(json.loads(dataForHash.decode("utf-16"))) 
pub_key = base64.b64decode(data['pub_key']) # Get PEM Public Key 

(utils.byteify() преобразует юникод строку в обычных строк)

Проверка подписи: определение

Authentication.verifySignature(signature, dataForHash, pub_key) 

Метод:

from Crypto.Signature import PKCS1_v1_5 
from Crypto.Hash import SHA256 
from Crypto.PublicKey import RSA 

def verifySignature(signature, data, pub_key): 
    key = RSA.importKey(pub_key) 
    h = SHA256.new(data) 
    verifier = PKCS1_v1_5.new(key) 
    return verifier.verify(h, signature) 

Однако подпись проверка возвращает False. Я также попытался использовать библиотеку m2crypto, но он возвращает 0.

ответ

0

Мне удалось найти проблему.

Несмотря на то что в Python (PyCrypto) функция знака должна получать хэш данных для подписи, используя API веб-криптографии, метод знака применяет хеш-функцию к полученным данным перед их подписанием.

Следовательно, данные в JS были хэшированы дважды, один перед вызовом метода знака и один в методе знака, прежде чем создавать подпись.

function signData(private_key, data, callback){ 

    var dataForHash = str2ab(JSON.stringify(sortObject(data))); 

    signRSA(private_key, dataForHash, function(data){   

     callback(data.buffer.b64encode(), dataForHash.b64encode()); 
    });  
} 

ArrayBuffer.prototype.b64encode = function(){ 
    return btoa(String.fromCharCode.apply(null, new Uint8Array(this))); 
}; 

String.prototype.b64decode = function(){ 
    var binary_string = window.atob(this); 
    var len = binary_string.length; 
    var bytes = new Uint8Array(new ArrayBuffer(len)); 
    for (var i = 0; i < len; i++)  { 
     bytes[i] = binary_string.charCodeAt(i); 
    } 
    return bytes; 
}; 

С этой модификацией проверка в python возвращает True сейчас.