Escondido à vista de Plain – Steganografia
Para nós, uma flor parece um toque de cor. Para uma abelha, é um mapa visual. Muitas flores têm padrões ultravioletas invisíveis para os seres humanos, mas claros para os polinizadores. Essas marcas agem como guias de pouso, direcionando as abelhas diretamente para o néctar. Flores UV, insetos disfarçados de folhas, polvos se misturando em coral … os segredos podem sentar -se em aberto, puro e chato, até que você saiba a chave que revela seu significado oculto. A natureza tem sido “ocultar” as informações dessa maneira há milhões de anos. Os humanos também aprenderam o mesmo truque: a melhor maneira de esconder uma mensagem não está apenas atrás de fechaduras ou códigos, mas dentro de algo que parece completamente comum. Os romanos, por exemplo, escreveram com leite que seco invisível, deixando uma carta que parecia em branco até aquecida. Para a maioria, era uma folha de pergaminho inocente, mas para o destinatário pretendido, revelou um segredo. Ao longo dos séculos, métodos como esse se tornaram mais sofisticados e, com a ascensão da era digital, a Steganografia encontrou oportunidades inteiramente novas. Hoje, bilhões de imagens são visualizadas on -line todos os dias e algumas delas podem estar carregando segredos. Vamos explorar o mundo fascinante da Steganografia. A Steganografia vem de várias formas e, da mesma forma à criptografia, conta com o remetente e o receptor que concordam com um método. Por exemplo, “A primeira letra de cada palavra revela a senha”. A diferença com a criptografia é a seguinte: com criptografia, você sabe que há uma mensagem oculta. Com a Steganografia, você pode não estar consciente que existe. Por exemplo, ocultar a senha “synwil” usando criptografia pode produzir algo como 4mjj0nWtsijjdbp+g9skrw == enquanto a Steganografia pode codificá -la em uma frase como: Vejo você na próxima semana em Londres. Mas os seres humanos são inteligentes, e métodos simples baseados em texto podem ser facilmente descobertos. Precisamos de algo maior, muito maior, onde pequenos bits podem ser alterados sem que ninguém percebesse. Às vezes, os pintores escondem sua assinatura aos olhos de um retrato, talvez possamos fazer algo semelhante com imagens digitais. Imagens grandes vêm com muitos pixels, e os pixels vêm com muitos bytes. Por exemplo, uma imagem de 1920×1080 tem mais de 2 milhões de pixels. Uma imagem BMP colorida de 24 bits usa 3 bytes (vermelho, verde, azul) por pixel, totalizando mais de 6 milhões de bytes. Cada pixel pode exibir 16,7 milhões de cores diferentes (2^(3*8)) e o olho humano não pode distinguir entre diferenças sutis. É exatamente isso que podemos explorar: alterando o bit menos significativo (LSB) de um byte, podemos incorporar uma mensagem secreta em uma imagem. No entanto, existem algumas precauções: as ferramentas podem detectar anomalias estatísticas, por isso é aconselhável primeiro criptografar a mensagem. Isso garante que, mesmo se descoberto, a mensagem permanece ilegível. Algoritmos mais sofisticados existem para mitigar esses riscos, mas não os cobriremos hoje. Escolher quais bits para flip também é crucial. Alterações seqüenciais são muito óbvias e o receptor ainda precisa reconstruir a mensagem. Isso exclui métodos simples e verdadeira aleatoriedade, deixando-nos com pseudo-randomidade. Usando um PRNG (gerador de números pseudo-aleatórios) com uma semente e ferramenta compartilhadas, o remetente e o receptor podem selecionar deterministicamente os mesmos bytes aparentemente aleatórios. Isso é poderoso: mesmo que a semente seja comprometida, o algoritmo para gerar os números permanece um mistério. Mas chega de teoria, vamos ver como isso fica em ação. Incorporando para incorporar a mensagem em um arquivo, primeiro a criptografamos e depois a transformamos nos bits individuais. Também embrulhamos o código em uma assinatura especial para que possamos identificar quando a mensagem é totalmente lida ao extrair: var bmp_header_bytes = 54 // Não devemos alterar esses start = “1 ::” var end = “> 0: Iniciar e tags finais payloadbytes: = []BYTE (START + ENCRYPTEDPAYLOAD + END) // Transforme a carga útil em bits var BitStringBuilder strings.builder bitstringbuilder.grow (len (payloadbytes) * 8) para _, b: = range payloadbytes {bitstringbuilder.writestring (fmt.st.stf (bittringbuilder.wringSl) bitstringbuilder.string () // A imagem de verificação é grande o suficiente disponível: = len (arquivo) – bmp_header_bytes se len (payloadbits)> disponívelbits {log.fatalf (“PayLoad do modo de seleção é muito grande para incorporar esta imagem”)} Digite o modo de tela inteira e a tela full -screen “PayLoadBits” é agora um stringn stringbits “é um stringn stringn. Agora inicializamos nosso gerador de números “aleatórios”. Ele retorna uma função que retorna a próxima posição para a semente e o arquivo fornecidos. Parecemos mais detalhadamente para isso mais tarde. getNextPosition: = startrng (semente, arquivo) Digite o modo de saída de tela cheia de tela cheia agora, agora passamos por cada bit da carga útil, pegue o byte do arquivo na posição determinada e substituímos seu bit final pelo nosso novo bit de carga útil. para _, bit: = range payloadbits {position: = getNextPosition () // Recuperar bits da próxima posição no arquivo binarystr: = bytetobinaryString (arquivo[position]) // Substitua o LSB Newbits: = Binarystr[:len(binaryStr)-1] + string (bit) // Escreva bits de volta ao arquivo[position] = BinaryStringTobyte (Newbits)} Digite o modo de saída de tela cheia de tela cheia, escrevemos o arquivo novamente e isso é tudo o que há para incorporar. Extraindo para extrair a mensagem novamente, fazemos o mesmo processo ao contrário. Em um loop infinito, passamos por cada posição usando a mesma função RNG e coletamos os bits. Cada 8 bits, podemos salvar um byte. Quando chegamos ao marcador final, quebramos o loop. getNextPosition: = startrng (semente, arquivo) bytebuffer: = “” var payloadBytes []BYTE Extrairdbits: = 0 maxbitstoextract: = len (arquivo) * 8 // máximo teórico absoluto para {// impedir o loop infinito se o marcador final não for encontrado se extraídobits> maxbitstoextract {log.fatal (“Limite de extração para encontrar o final do final do final. : = bytetobinaryString (arquivo[position]) bytebuffer += binarystr[len(binaryStr)-1:]
Extractedbits ++ // Uma vez que temos um byte completo … se Len (ByTeBuffer) == 8 {// … Anexe byte à nossa carga útil final Charbyte: = BinaryStringTobyte (BYTEBUFFER) PayloadBytes = Append (PayloadBytes, Charbyte) len (start) && carga útil! = Iniciar {log.fatal (“Iniciar a mensagem não corresponde. Semente/sal provavelmente incorreta.”)} // quebra se o marcador final foi detectado se strings.HASSUFFIX (MODO DO MODO, END) {Break}}}} DOLLOGER: = String (DOMPRENCERBYTES) // TRIM START e End) “Startrng” retorna “getNextPosition”. Isso é para que ele possa acompanhar variáveis específicas, como o contador e a posição anterior usada. “GetNextPosition” cria uma semente única usando a posição e contador anterior para evitar repetir as mesmas posições. Ele também usa os meta dados da imagem para tornar as posições exclusivas para cada imagem. funct startrng (string de semente, arquivo []byte) func () uint64 {viu: = make (mapa[uint64]bool) contador: = 0 var anteriorPOS UINT64 return func () uint64 {para {imagansize: = len (file) // crie uma semente exclusiva exclusiva: = semente + strconv.formatuint (anteriorpo, 10) + “$#” + string (arquivo[:BMP_HEADER_SIZE]) + String (Imagesize) + “:” + strConv.itoa (contador) pos: = prng (exclusivo, imagense) anteriorpo = pos contador ++ // verificação de segurança para evitar reutilizar posições se! visto[pos] { visto[pos] = True Return pos}}}} // Com base na semente exclusiva, obtenha a posição dentro do tamanho da imagem disponível Func PRNG (String de semente, imagensize int) uint64 {modifyableImagesize: = Imagesize – BMP_HEADER_SIZE HASHER: = SHA256.New () Hasher.itE ([]Byte (semente)) SEEDHASHSTR: = Hex.EncodetoString (Hashher.sum (NIL))[0:16]
SEEDHASH, ERR: = strConv.Parseuint (SeedHashstr, 16, 64) se err! = nil {Log.fatal (err)} Retornar SEEDHASH%UINT64 (ModifyableImagesize) + UINT64 (BMP_Header_Size)} Digite o modo de tela de tela cheia Exit. Para o código completo, consulte
Fonte