Quisiera abrir el siguiente hilo para saber si es posible determinar la paridad de un punto en una curva Eliptica utilizada en criptografía.
Encontré un video en youtube donde un programador de C# afirma tener la formula para determinar si un punto dado es par o impar para una curva en especifico.
Tiene una pagina
:http://remon78eg.tk/curve/mod2/
Utiliza un valor P custom: 115792089237316195423570985008687907853269984665640564039457584007908834675927
El cual afirma que es un valor débil o vulnerable.
El usuario no revela mucho de su método o test de paridad de un punto o publickey.
Las preguntas aquí son las siguientes: ¿Qué tiene de débil o vulnerable su orden de la curva? ¿Cuál seria el test de paridad que se pueda implementar para determinar si un punto (X,Y) pertenece a una privatekey par o impar?
El balance actual de los desafios 969 Bitcoin (29 Millones USD a la fecha de hoy 16 de Abril 2023).
Numero total de desafios es de 160 de los cuales ya fueron reclamados 76 quedando pendiente 84, la dificultad de los mismos es exponencial y cada desafio es el doble de dificl que el anterior.
Muy buen día a todos últimamente hablando con Kub0x sobre curvas elípticas me sugirió publicar aquí los rompecabezas existentes de bitcoin, hay aproximadamente 12 bitcoin en premios. Para los rompecabezas Importantes y algunos otros bitcoin para rompecabezas pequeños.
Los rompecabezas se puede abordar de varias formas, pero abordarlos por fuerza bruta es casi imposible a no ser que tengan mucha mucha mucha suerte (El tema de Fuerza bruta exclusiva no va a ser tratado aqui).
Estos rompecabezas fueron hechos con el propósito explicito de ser crackeados desde el 2015 y en caso de conseguirlo pueden tomar el bitcoin de premio que se encuentra ahi, ya que el autor para eso los creo, fueron creados cuando el bitcoin se cambiaba por 160 Dolares cada uno, hoy en dia cuesta cada uno mas de 40 Mil dólares
A continuación los rompecabezas en el siguiente formato:
Código:
#Numero de Bits ( Dirección public de bitcoin ) Monto actual de la cartera Inicio del rango del privatekey Fin del rango del privatekey Llave publica en formato comprimido
Para quienes piensen abordar el puzzle por fuerza bruta, estos son mas o menos los tiempos estimados para escanear el rango completo de acuerdo a la velocidad conseguida:
Código:
Puzzle 120 @ 1 Terakeys/s : 21074771622667996 años Puzzle 120 @ 1 Petakeys/s : 21074771622667 años Puzzle 120 @ 1 Exakeys/s : 21074771622 años Puzzle 120 @ 1 Zettakeys/s : 21074771 años Puzzle 120 @ 1 Yottakeys/s : 21074 años Puzzle 125 @ 1 Terakeys/s : 674392691925375886 años Puzzle 125 @ 1 Petakeys/s : 674392691925375 años Puzzle 125 @ 1 Exakeys/s : 674392691925 años Puzzle 125 @ 1 Zettakeys/s : 674392691 años Puzzle 125 @ 1 Yottakeys/s : 674392 años Puzzle 130 @ 1 Terakeys/s : 21580566141612028377 años Puzzle 130 @ 1 Petakeys/s : 21580566141612028 años Puzzle 130 @ 1 Exakeys/s : 21580566141612 años Puzzle 130 @ 1 Zettakeys/s : 21580566141 años Puzzle 130 @ 1 Yottakeys/s : 21580566 años Puzzle 135 @ 1 Terakeys/s : 690578116531584908094 años Puzzle 135 @ 1 Petakeys/s : 690578116531584908 años Puzzle 135 @ 1 Exakeys/s : 690578116531584 años Puzzle 135 @ 1 Zettakeys/s : 690578116531 años Puzzle 135 @ 1 Yottakeys/s : 690578116 años Puzzle 140 @ 1 Terakeys/s : 22098499729010717059011 años Puzzle 140 @ 1 Petakeys/s : 22098499729010717059 años Puzzle 140 @ 1 Exakeys/s : 22098499729010717 años Puzzle 140 @ 1 Zettakeys/s : 22098499729010 años Puzzle 140 @ 1 Yottakeys/s : 22098499729 años Puzzle 145 @ 1 Terakeys/s : 707151991328342945888372 años Puzzle 145 @ 1 Petakeys/s : 707151991328342945888 años Puzzle 145 @ 1 Exakeys/s : 707151991328342945 años Puzzle 145 @ 1 Zettakeys/s : 707151991328342 años Puzzle 145 @ 1 Yottakeys/s : 707151991328 años Puzzle 150 @ 1 Terakeys/s : 22628863722506974268427923 años Puzzle 150 @ 1 Petakeys/s : 22628863722506974268427 años Puzzle 150 @ 1 Exakeys/s : 22628863722506974268 años Puzzle 150 @ 1 Zettakeys/s : 22628863722506974 años Puzzle 150 @ 1 Yottakeys/s : 22628863722506 años Puzzle 155 @ 1 Terakeys/s : 724123639120223176589693541 años Puzzle 155 @ 1 Petakeys/s : 724123639120223176589693 años Puzzle 155 @ 1 Exakeys/s : 724123639120223176589 años Puzzle 155 @ 1 Zettakeys/s : 724123639120223176 años Puzzle 155 @ 1 Yottakeys/s : 724123639120223 años Puzzle 160 @ 1 Terakeys/s : 23171956451847141650870193314 años Puzzle 160 @ 1 Petakeys/s : 23171956451847141650870193 años Puzzle 160 @ 1 Exakeys/s : 23171956451847141650870 años Puzzle 160 @ 1 Zettakeys/s : 23171956451847141650 años Puzzle 160 @ 1 Yottakeys/s : 23171956451847141 años
Si tienen alguna duda favor de comentarla en este hilo.
He creado un canal privado de Telegram, si alguno gusta discutir el tema ahí, favor de enviarme mensaje privado a https://t.me/albertobsd y si lo considero oportuno los agregare al grupo.
Take Bobby's Bitcoin
WEB:
Estos son 2 Desafios
#1 Wallet con 1.0 BTC Public Address: 1JxWyNrkgYvgsHu8hVQZqTXEB9RftRGP5m Private Key: 6PnQmAyBky9ZXJyZBv9QSGRUXkKh9HfnVsZWPn4YtcwoKy5vufUgfA3Ld7 BIP-38 Passphrase: ???
#2 Wallet con 1.0 BTC Public Address: 1QGtbKxx6FKDD66LwnrzHCAHmyZ7mDHqC4 Private Key: ??? BIP-38 Passphrase: 594Y-L2RW-4ME7-2XVX-9B41 BIP-38 Confirmation Code: cfrm38VUh2i5qzzCqedWtc8ekFxT3UpcQnfb42JRrLbTWCRTfgVTCXqLp3FYxqiyQDo4D3DyWzY
Ok, veamos necesito una forma eficiente de ordenar un archivo de de 100 GB, Cada registro del archivo son 36 Bytes en binario.
Usualmente lo hacia con archivos pequeños 10 o 5 GB pero en RAM. Esto con el algoritmo Introsort y es bastante eficiente, pero ahora estoy utilizando el mismo método pero en Disco duro ya que el archivo es muy grande, Lo que estoy haciendo es leer los registros del disco, cargarlos en memoria, compararlos y escribir en disco en caso de que necesiten ser ordenados. Este proceso es muy lento directo en el disco duro.
Podría tratar de dividir el proceso he ir cargando de 10 en 10 GB en RAM u otra cantidad ordenarlos en memoria y seguir con los demás pedazos, sin embargo el problema es ordenar entre pedazos separados.
El proceso de generación de registros es aleatorio y no se en que orden se generaran los registros, quiero hacer este proceso lo mas eficiente y rápido posible, ya que si funciona este archivo tendré que generar un archivo similar de 500 o 1000 GB. No tengo problemas de Espacio en disco.
¿Alguna idea adicional a hacerlo directo desde el disco duro?
Edit:
Ayer miestras publicaba este teme tambien pense en la solucion, pero no queria publicarla hasta implementarla.
Dado que la generación de los registros es aleatoria y es uniforme entre el rango de A a B entonces se me ocurre que una vez generado el archivo de 100 GB, dividir el rango de A a B en subrangos manejables en RAM por decil algo tengo los siguientes rangos para registros de 32 bytes:
Código:
From 0000000000000000000000000000000000000000000000000000000000000000 to 0ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc From 0ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc to 1999999999999999999999999999999999999999999999999999999999999998 From 1999999999999999999999999999999999999999999999999999999999999998 to 2666666666666666666666666666666666666666666666666666666666666664 From 2666666666666666666666666666666666666666666666666666666666666664 to 3333333333333333333333333333333333333333333333333333333333333330 From 3333333333333333333333333333333333333333333333333333333333333330 to 3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc From 3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc to 4cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc8 From 4cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc8 to 5999999999999999999999999999999999999999999999999999999999999994 From 5999999999999999999999999999999999999999999999999999999999999994 to 6666666666666666666666666666666666666666666666666666666666666660 From 6666666666666666666666666666666666666666666666666666666666666660 to 733333333333333333333333333333333333333333333333333333333333332c From 733333333333333333333333333333333333333333333333333333333333332c to 7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 From 7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8 to 8cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc4 From 8cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc4 to 9999999999999999999999999999999999999999999999999999999999999990 From 9999999999999999999999999999999999999999999999999999999999999990 to a66666666666666666666666666666666666666666666666666666666666665c From a66666666666666666666666666666666666666666666666666666666666665c to b333333333333333333333333333333333333333333333333333333333333328 From b333333333333333333333333333333333333333333333333333333333333328 to bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 From bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4 to ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc0 From ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc0 to d99999999999999999999999999999999999999999999999999999999999998c From d99999999999999999999999999999999999999999999999999999999999998c to e666666666666666666666666666666666666666666666666666666666666658 From e666666666666666666666666666666666666666666666666666666666666658 to f333333333333333333333333333333333333333333333333333333333333324 From f333333333333333333333333333333333333333333333333333333333333324 to ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Entonces buscamos en el archivo los valores que entren en alguno de los rango anteriores, se ordenan en RAM y se escriben en un archivo aparte. Una vez completado el proceso para todos los sub-rangos se unen los archivos en uno solo y se borra el archivo desordenado.
Esto se puede hacer así debido a que la distribución de los registros es uniforme en el rango original de A a B, en caso de que la data este sesgada y existan mas valores en un sub-rango dado es conveniente poner un limite de cantidad de registros leídos para que el mismo no sobrepase la cantidad de RAM.
Pues nada compañeros esta próxima semana cumplo 15 años registrado en el foro.
Yo se que tengo mas años viendo el foro, sin embargo hasta ese momento abrí mi cuenta.
Quiero agradecer a todos los miembros de este foro, a los que ya no están y a los que aun siguen. En este foro he aprendido mucho, de muchos temas distintos, aunque sea un poco de todo, estoy muy agradecido.
Este tipo de Ataque tiene ciertas condiciones iniciales para ser llevado acabo.
El cliente solo puede saber si su paquete fue aceptado o no.
Esto es debido al check que hace el servidor sobre el mensaje recibido
El servidor no Cambia de KEY utilizada durante el proceso de cifrado y descifrado.
Esto es debido a una mala implementación, ya que el servidor debería de renovar el KEY cada X tiempo y con cada cliente distinto.
El servidor tiene algún leak de información ya sea por error o mediante otro tipo de ataque.
El cliente solo podrá descifrar Una parte de la información, excepto por el Bloque inicial
Dejo a continuación una imagen de prueba y el código, proximamente subire un video hablando del tema.
Codigo, este codigo ejemplifica el cliente y servidor mediante un hilo distinto, lo hice de esta manera para no complicarme con el protocolo en RED de los mismo, se puede hacer sin hilos, y solo con llamadas a funcion, pero la idea es garantizar que el cliente no tiene acceso al servidor.
No sabemos qué pasará en el futuro, es decir no sabemos si nos robaran la cartera o la perderemos en algún USB y alguien la encontrara. Tampoco sabemos la cantidad de poder de computo que existira.
Pero además de tener cifrada nuestra cartera con un buen passphrase de más de 40 caracteres, se puede lograr una mejor seguridad, para en el caso de que sea robada sea inviable que por medio de fuerza bruta directo contra el passphrase.
Nuestra Cartera está protegida con el resultado de un hash sha512 derivado N veces a partir de nuestro Passphrase y un salt.
Normalmente el cliente bitcoin-core calcula ese N de tal forma que la Operación en total no lleve más de 1 Segundo
¿Por que? ¿Por que ponérsela fácil a los crackers de wallets?
Se puede editar el código fuente del bitcoin-core de tal forma que cuando nosotros cambiemos el passphrase este utilice un número N tal que N el proceso completo de PBKDF2_algo lleve al menos uno o dos minutos por passphare, es un pequeño precio de espera. Y el resultado será sumamente desalentador para quien se robe o encuentre la cartera.
¿Como hacer esta modificacion?
Si revisamos la versión estable y actual al dia de hoy, el bitcoin core 0.20 el archivo wallet.cpp tiene la solución:
Si quitamos todo lo relacionado con el calculo del tiempo y agregamos la linea:
Código
pMasterKey.second.nDeriveIterations=133707331;
En mi caso con el bitcoin-core oficial recompilado y con un procesador Intel Xeon CPU E3-1271 v3 @ 3.60GHzcambiar el passphrase toma alrededor de un minuto
Bueno esta investigación comenzó a manera de broma y solo por hobby. En las platicas que tenemos en la comunidad de elhacker.net en Telegram ( https://t.me/elhackerdotnet )
Se menciono hace tiempo la existencia de una cartera de bitcoin con 69 Mil BTC, al tipo de cambio actual hoy 4 de Noviembre de 2020 serian unos 995 millones de dólares, entre bromas se menciono que teníamos que crackearla con algún computador cuántico.
En fin, el proceso "normal" para abrir una cartera cifrada utilizando las aplicaciones oficiales de Bitcoin-Core es el siguiente.
Primero cargamos la cartera
Código:
bitcoin-cli loalwallet "wallet.dat"
"wallet.dat" es un archivo que debe de existir en el directorio ~/.bitcoin/wallets/
Se puede llamar de otro modo, el punto es que debe de exisitir en ese path
Segundo desbloqueamos la cartera con nuestra passphrase o mas comúnmente contraseña
Código:
bitcoin-cli walletpassphrase "passphrase o password" 60
Entre comillas tenemos nuestro password y el 60 a continuación indica que desbloqueamos la cartera por 60segundos
Si el password es correcto no marcara error, de lo contrario lo indicará.
Código:
error code: -14 error message: Error: The wallet passphrase entered was incorrect.
Ahora la forma lenta e ineficiente de intentar crackearla por fuerza fruta probando directamente distintos passphrase desde la misma terminal. Sigue siendo lento incluso aunque se utilice algún script bash por que pasar del bash al programa y de regreso es ineficiente.
Necesitamos saber que hace internamente la aplicación, para tratar de reproducirlo en un programa en C y ejecutarlo por aparte posiblemente con multihilo para mejorar la eficiencia
¿Que hace el bitcoin core con nuestro passphrase?
Nuestro passphrase es combinado con un salt que se encuentra almacenado en el archivo, mediante un algoritmo estilo PBKDF y con mas de 25000 iteraciones generan un hash sha512.
De estos 64 bytes generados mediante PBKDF, se utilizan los primeros 32 bytes como KEY para inicializar el contexto de AES y los siguientes 16 bytes como IV para el algoritmo CBC
A este algoritmo AES256CBC se le pasa como parámetro para descifrar el mKey (master KEY) cifrado y se obtiene un mKey Descifrado
El master key ya descifrado se le hacen varias pruebas, se utiliza este valor como KEY para otros descifrados y en este caso como IV en todas las pruebas se utilizan 16 bytes del public Key de la cartera bitcoin obtenidos por una función interna llamada GetHash que desconozco que valores devuelva exactamente, solamente me limite a llamarla.
Y si el master key ya descifrado pasa todas las pruebas se almacena en memoria para sea utilizado en el futuro.
Fin de la triste Historia.
Resumen en pseudo codigo
El siguiente codigo en Pseudo C esta solo para representare que hace la aplicación internamente.
Código
prekey = PBKDF(passphrase,IV, N Iteraciones,"sha512");
Entonces si nuestro plan es un ataque por fuerza bruta podemos saltarnos el PBKDF que se ejecuta N Iteraciones (Mínimo 25000) y saltar directamente al Decrypt de AES.
Tenemos 2 opciones:
1.- Generar un par (KEY,IV) 48 bytes random o secuencial y empezar con el primer AES256CBC_decrypt y utilizar el valor generado para continuar con los AES256CBC_decrypt dentro del for.
2.- O generar solamente un KEY de 32 bytes random o secuencial y pasar directamente a los AES256CBC_decrypt dentro del For.
Asi con 32 bytes solo tenemos 1 de 115792089237316195423570985008687907853269984665640564039457584007913129639936 posibilidades de dar con la KEY correcto. xD xD xD
Resultados vistos en la práctica.
Con la opción 1 solamente el 0.4% de los valores aleatorios generados pasaban el primer AES256CBC_decrypt posteriormente solo el 0.4% de esos valores pasaban el primer AES256CBC_decrypt dentro del FOR
Para la cartera que cree con el propósito de realizar las pruebas los challenge dentro del FOR eran sobre 500.
Sin embargo para la cartera lackeada con 69K BTC solo está disponible un solo challenge dentro del FOR, al ser solo dos AES256CBC_decrypt me dio bastantes KEY "Falsos positivos" aproximadamente uno de cada millón de valores random generados (KEY,IV) pasaban ambas pruebas
En conclusión
La aproximación por Fuerza Bruta a AES256CBC es improbable que funcione ojo, improbable no imposible, Tal vez en el futuro con mejor poder de computo disponible, o tal vez con Múltiples equipos trabajando de forma sincronizada con alguna RED tipo BOINC o algún tipo de BOTNET
Tengo el código utilizado para realizar este proceso, un poco de manera hardcodeada Ya que los Valores cifrados los saque directamente mediante Hexedit, si alguien esta interesado en la estructura del archivo no dude en comentarlo.
Anteriormente no me había fijado la salida del descifrado por AES 256 CBC con Pad habilitado.
Normalmente uno solo espera la data original descifrada, vamos que si ciframos la palabra "hola" esperamos de vuelta la misma palabra "hola" ya descifrada.
Cuando encriptas sin padding cada bloque del tamaño "AES_BLOCKSIZE" devuelve la misma cantidad de bloques. Pero el cifrar con Padding agrega cierta cantidad mas de datos.
Por ejemplo si ciframos 32 bytes con AES256CBC con Padding nos devuelve un buffer con 48 bytes de data
Y cuando desciframos esos 48 bytes, nos devuelve la data original de 32 bytes + un buffer "sucio" es decir que hay mas datos en el buffer, en mi caso he comprobado que para este ejemplo siempre devuelve un buffer sucio de 16 bytes y cada uno de esos bytes tiene valor de uno.
Mi pregunta es ¿Es normal esto, o solo es la forma en la que trabaja la librería ctaes?
hice un programa que muestra que independientemente del key y del IV utilizados siempre pasa lo mismo
Código:
albertobsd $ ./test_aes256cbc key: fd792d4458dbc9bfee589482273ae061a37e24a72e95a0a5fba17109e4cb1daf iv: 7d5559d5e50e340bb66618ceaad7ed1b Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA len 48 cipher data 1117fcb2cbb27ee2f735ce4083d0aea743b51f6b7f61f59ce5a27a78bb5d454eab8b6a1733a5ad1d07b0b08ba1732e04 len 32 decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010 albertobsd $ ./test_aes256cbc key: 1049354727fa2affd4410da40870f1757e211efeb96349b8576157c101fe5ab0 iv: 49547b6aac189b8487f60157d13185df Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA len 48 cipher data e980ef82804a6fe5bec15dda0ad50064457c65259cd810055c38eb7c55e1d40071646c7c792e6d5a7ac6597057868267 len 32 decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010 albertobsd $ ./test_aes256cbc key: 6d40ce0be48da5fcc7ede6531dae1b3613e5931a808e1ae99928ab74f74f3685 iv: ec1cebfa7894563a8329aa797610841c Data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA len 48 cipher data 395976ca9f00ace59ba64e8a1ee5dbaf55f45e786fada6520148d82a84c298e15b2854763a2fc82e7a62164936bf8f1f len 32 decipher data 414141414141414141414141414141414141414141414141414141414141414110101010101010101010101010101010
De ser normal esto se podría tomar ese buffer sucio como una comprobación de que la key y el iv utilizados son los correctos?
Publico este tema aquí, ya que no se en qué sección queda mejor publicarlo.
Estoy intentando extraer la información Cifrada de una cartera bitcoin, en específico la información del Key para posteriormente intentar descifrarlo por algún ataque de fuerza bruta.
Quiero extraerla por que no quiero depender del bitcoin core ya que si se realiza el ataque por fuerza bruta mediante algún script bash o algun otro metodo NO compilado, el ataque puede ser realmente ineficiente.
También quiero brincarme algunos pasos innecesarios de funciones tipo rehash o PBKDF2 (key derivation) ya que aunque no consumen mucho CPU si quitan algunos miles de ciclos de procesamiento que a la larga pueden hacer aun mas eterno el proceso de crackeo.
Segun he leido la informacion del Key cifrado el salt y el numero de iteraciones esta contenida en un campo de 64 bytes del wallet.dat llamado mkey.
mkey - a size prefixed string denoting the start of the master key data.
nID - an integer whose purpose I have been unable to determine.
encrypted_key - a size prefixed buffer containing the encrypted master key.
salt - a size prefixed buffer containing the salt data used when encrypting the key.
derivation_method - an integer containing either 0 or 1 for the method used to encrypt the master key using the wallet password.
derivation_rounds – an integer containing the number of rounds used to encrypt the master key.
other_derivation_parameters
mkey es solo el ascii "mkey", se que el encrypted_key debe de ser de 32 bytes y el salt de 16, restando solo 12 bytes para los otros datos, sin embargo no estoy seguro del orden de los mismos.
Si vemos la siguiente imagen:
Vemos que ahí esta la data, escribí un pequeño programa que la encuentra y la extrae, pero no se en que orden este, con ver los datos de esta cartera y otras me doy cuenta de algunos datos que pueden ser números como los primeros 8 bytes después del mkey, pueden ser números, al igual que los últimos 4 antes de ckey.
Edit
Solucionado el master key cifrado son 48 bytes que se encuentran a un offset de -72 bytes de la primera coincidencia del string mkey.
Para esta cartera en cuestión el Master Key Cifrado es:
Todo esto viene del análisis que estoy realizando al código fuente del Bitcoin Core.
Hoy hablaré sobre la función BytesToKeySHA512AES la cual es una de las primeras que se utilizan cuando intentas desbloquear una cartera bitcoin protegida con un passphrase.
BytesToKeySHA512AES básicamente toma las passphrase ingresada + un salt proporcionado por el mismo archivo wallet.dat y los transforma en un (key, iv) para posteriormente utilizarlos como material para descifrar la llave cifrada.
El código fuente de BytesToKeySHA512AES, lo pueden encontrar en
Tiene 3 parámetros de entrada y 2 de salida Entrada: Salt Passphrase Count
Salida: Key IV
La parte interesante del código es la siguiente:
Código
for(int i =0; i != count -1; i++)
di.Reset().Write(buf,sizeof(buf)).Finalize(buf);
Básicamente obtiene el hash sha512 de si mismo (count -1) veces ya la que primera vez fue el hash sha512 de (passphrase + IV) como muestra el siguiente código:
Lo escribí en PHP ya que es mas fácil darle seguimiento a las funciones hash, solo que no estoy 100% seguro de como manejar las copia de los bytes del hash resultante al key y al IV respectivamente.