8

I am having a use case where i am downloading the file from URL using GET request. Is it possible to calculate SHA256 of file stream without saving to disk or holding an entire object in memory?

Rajeev
  • 4,762
  • 8
  • 41
  • 63

3 Answers3

4

This can be accomplished with a MessageDigest and Sink.fold.

First we need a function to create an empty digest and a function to update a digest with a ByteBuffer:

import java.security.MessageDigest
import java.nio.ByteBuffer

def emptySHA256Digest : MessageDigest = MessageDigest getInstance "SHA-256" 

val updateDigest : (MessageDigest, ByteBuffer) => MessageDigest = 
  (messageDigest, byteBuffer) => {
    messageDigest update byteBuffer
    messageDigest
  }

These two functions can then be used within a fold which is applied to the entity of an HttpResponse to update the digest with all ByteString values in the entity:

import akka.http.scaladsl.model.HttpResponse

val responseBodyToDigest : HttpResponse => Future[MessageDigest] = 
  (_ : HttpResponse)
    .entity
    .dataBytes
    .map(_.asByteBuffer)
    .runFold(emptySHA256Digest)(updateDigest)
Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
  • given answer is producing the wrong sha256 value. Is it calculating before stream completes? test code : https://gist.github.com/rajeevprasanna/079813d9951da3016828b83f8fd09695 – Rajeev Jul 26 '17 at 07:41
2

You would need Flow which will transform one data to another data. In your case, you want to transform plain text to sha256 text.

def digest(algorithm: String = "SHA-256"): Flow[ByteString, ByteString, NotUsed] = {
    Flow[ByteString].fold(MessageDigest.getInstance(algorithm)) {
        case (digest: MessageDigest, bytes:ByteString) => {digest.update(bytes.asByteBuffer); digest}}
          .map {case md: MessageDigest => ByteString(md.digest())}
}
Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
Abdhesh kumar
  • 97
  • 1
  • 5
1

Use one of MessageDigest.getInstance("SHA-256").update methods.

Pass your file piece-by-piece to it.

Then call digest()

Sample code:

    MessageDigest instance = MessageDigest.getInstance("SHA-256");
    for(byte[] arr: source){
        instance.update(arr);
    }
    byte[] result = instance.digest();
talex
  • 17,973
  • 3
  • 29
  • 66