Я хотел реализовать собственное шифрование для своего приложения. Я сделал капитальный ремонт этого поста. До сегодняшнего дня у меня действительно не было времени заняться этим. Надеюсь, это будет более полезным, чем мой оригинал. Потратил невероятное количество времени на эту проблему. Надеюсь, это время поможет спасти других.
При этом я столкнулся с несколькими проблемами. Я не осознавал, что происходит, до самого конца. Я получал разные общие секреты, а позже и некоторые исключения.
Вот что я пробовал:
- Использовались встроенные средства, предоставляемые обоими языками. Не мог понять, как преобразовать необработанный открытый ключ в форму, которую могла бы использовать Java.
- Поцарапал это и пошел с простыми формулами для расчета открытых и закрытых ключей для каждой стороны. (Статистически это могло сработать примерно в 25% случаев ... к счастью для меня, нет.)
- Погрузился в документацию по ASN.1 от ITU и отправил открытый ключ Erlang, закодированный аналогично ключам Java. Определял это сохранением ключа Java в файл и использованием шестнадцатеричного редактора. Я не стал возвращаться к подробному тестированию. Он избавился от
java.security.spec.InvalidKeySpecException: Inappropriate key specification
. Думаю, здесь статистика тоже не в мою пользу. Секреты все еще не совпадали. - Отправил все числа из Java на сторону Erlang для вычисления ключей, общий секрет с использованием чисел Java ... Те же числа. Есть надежда!!!
- Начали внимательно изучать передаваемые данные. Это заняло немного времени, поскольку в Erlang данные организованы в байты без знака. Eclipse IDE (возможно, есть параметр, который нужно изменить) использует байты со знаком в байтовых массивах и массив целых чисел со знаком в
BigInteger
.
Здесь я начал видеть вещи. Все это вводилось вручную в течение многих итераций, чтобы убедиться, что я нашел правильный шаблон событий. В Erlang я вижу свой открытый ключ, начинающийся с <<215, 101, 208, 153,
. Первый элемент BigInteger
на стороне Java - это 681193318
. Буфер, в который были прочитаны байтовые данные, читает: [-41, 101, -48, -103
. (То же, что и у Эрланга). Однако, потратив время, преобразуйте первые четыре элемента двоичной строки в целое число ...
<<I:32/signed-integer>> = <<215,101,208,153>>.
Это дает -681193319
по сравнению с большим целым числом 681193318
Код, который я использовал, был довольно простым:
Erlang "Сервер":
-module(echo).
-export([start/0]).
start() ->
crypto:start(),
spawn(fun () -> {ok, Sock} = gen_tcp:listen(12321, [binary, {packet, raw}]),
echo_loop(Sock)
end).
echo_loop(Sock) ->
{ok, Conn} = gen_tcp:accept(Sock),
io:format("Got connection: ~p~n", [Conn]),
Handler = spawn(fun () -> handle(Conn) end),
gen_tcp:controlling_process(Conn, Handler),
echo_loop(Sock).
p() ->
16#ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff.
g() ->
2.
handle(Conn) ->
receive
{tcp, Conn, Yc} ->
Xs = crypto:strong_rand_bytes(64),
Ys = crypto:mod_pow(g(),Xs,p()),
S = crypto:mod_pow(Yc, Xs, p()),
AESKey = crypto:hash(sha256, S),
gen_tcp:send(Conn, Ys),%KeyCert),
handle(Conn);
{tcp_closed, Conn} ->
io:format("Connection closed: ~p~n", [Conn])
end.
Java "Клиент":
public class MyProgram {
private static Socket s;
private static OutputStream out;
private static InputStream in;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MessageDigest hash;
byte buffer[] = new byte[1024];
byte buf2[];
int len = 0;
byte[] aeskey;
try {
hash = MessageDigest.getInstance("SHA-256");
byte keybuffer[] = new byte[64];
SecureRandom srnd = SecureRandom.getInstance("SHA1PRNG");
BigInteger Xc, Yc, Sc, Ys;
srnd.nextBytes(keybuffer);
Xc = new BigInteger(keybuffer);
Yc = new BigInteger("2").modPow(Xc, DiffieHellman.Group2.P);
s = new Socket("localhost",12321);
out = s.getOutputStream();
in = s.getInputStream();
out.write(Yc.toByteArray());
out.flush();
len = in.read(buffer);
buf2 = new byte[len];
System.arraycopy(buffer, 0, buf2, 0, len);
Ys = new BigInteger(buf2);
Sc = Ys.modPow(Xc, DiffieHellman.Group2.P);
aeskey = hash.digest(Sc.toByteArray());
out.close();
in.close();
s.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Что случилось?
{packet, raw}
(или эквивалентно{packet, 0}
), вы сообщаете erlang, что вы позаботитесь о сборке неопределенного количества фрагментов в полные данные, поэтому erlang просто помещает каждый фрагмент в отдельное сообщение. См. Здесь: stackoverflow.com/questions/43957164 /. Я не знаю, вызывает ли вышеперечисленное какие-либо из ваших проблем, но это то, что вам нужно решить. - person 7stud   schedule 22.07.2018{packet, 2}
, я думаю, что erlang, возможно, ожидает чего-то, чего я не предоставил в своем приложении Java, и зависает бесконечно. Я использовал1
, и это привело к успешной передаче, но ключи были на 1 байт длиннее на стороне Java. Больше вещей, которыми нужно управлять. - person Nolan Robidoux   schedule 23.07.2018