RSA 2048 on XMEGA : Timeout in OpenADC capture

Hello,

I have been trying to capture traces of RSA 2048 with my ChipWhiperer. Capturing traces for RSA with keys of length less or equal than 1024 works for me (although sometimes the traces don’t get captured), but I can’t make it work for key lengths greater than 1024. What I basically did was add some lines like simpleserial_addcmd('r', 64, get_pt); in simpleserial-rsa.c, and call target.simpleserial_write('r', key) repeatedly until I get a valid trace.
My whole capture function is the following (adapted from CW305_ECC_part1 demo):

lenkey=256

key = bytearray([np.random.randint(0,256) for i in range(lenkey)])
text = bytearray([0x05 for _ in range(16)])
target.flush()
scope.arm()
if(lenkey==16):
    target.simpleserial_write('p', key)
elif(lenkey==32):
    target.simpleserial_write('q', key)
elif(lenkey==64):
    target.simpleserial_write('r', key)
elif(lenkey==128):
    target.simpleserial_write('s', key)
elif(lenkey==256):
    target.simpleserial_write('u', key)

ret = scope.capture()

TOTAL_CYCLES = scope.adc.trig_count
scope.adc.samples = 24000

diffoff = 2450
rangeoff=100

def get_traces(N=50):
    traces = []
    offtraces = []
    segments = math.ceil(TOTAL_CYCLES / scope.adc.samples)
    print(segments)
    for i in trange(N, desc='Capturing traces'):
        scope.adc.offset = 0 
        wave = np.array([])
        for j in trange(segments, desc='portion'):
            ret=True
            shiftbool=1
            while(ret==True or shiftbool!=0):
            
                target.flush()
                scope.arm()
                if(lenkey==16):
                    target.simpleserial_write('p', key)
                elif(lenkey==32):
                    target.simpleserial_write('q', key)
                elif(lenkey==64):
                    target.simpleserial_write('r', key)
                elif(lenkey==128):
                    target.simpleserial_write('s', key)
                elif(lenkey==256):
                    target.simpleserial_write('u', key)
                ret = scope.capture()
                
                lasttrace = scope.get_last_trace()
                if(offtraces == []):
                    shiftbool=0
                elif(ret==False):
                    shiftbool = shift(offtraces[-1],lasttrace,rangeoff,diffoff)

            if ret:
                print("Failed capture")
                continue
                
            lasttrace = scope.get_last_trace()
            offtraces.append(lasttrace)
            wave = np.append(wave, lasttrace)
            
            scope.adc.offset += scope.adc.samples - diffoff

        traces.append(wave)

    return offtraces

What I get is only

(ChipWhisperer Scope WARNING|File _OpenADCInterface.py:642) Timeout in OpenADC capture(), no trigger seen! Trigger forced, data is invalid. Status: 0b
(ChipWhisperer Scope WARNING|File _OpenADCInterface.py:642) Timeout in OpenADC capture(), no trigger seen! Trigger forced, data is invalid. Status: 08

Did I do something wrong? How can I fix this?

Thanks in advance,
Slangster

There’s probably a number of things that are not right here.

First, the get_pt() function only processes 16 bytes, unless you modified it (https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/simpleserial-rsa/simpleserial-rsa-xmega.c#L333).

Second, once you do modify get_pt() to process a larger key size, it will run EXTREMELY SLOWLY on the xmega, so you’ll have to increase scope.adc.timeout so that you don’t get those timeouts anymore.

Finally, I don’t see your C code but if all those p/q/r… commands are registered to call the same get_pt() function, that probably isn’t going to work as you expect. When you register a simpleserial command with simpleserial_addcmd, the length of the input needs to be constant.

Sorry, I forgot to mention I had changed the get_pt() function, the 333rd line you’re referring to was changed to for(i = 0; i < len; i++) {

For your third point, my simpleserial_addcmd commands all require a constant length, so shouldn’t that work? I already tested for powers of 2 from 16 to 1024 and it works fine.
the addcmd I used are as follows :

simpleserial_addcmd(‘p’, 16, get_pt);
simpleserial_addcmd(‘q’, 32, get_pt);
simpleserial_addcmd(‘r’, 64, get_pt);
simpleserial_addcmd(‘s’, 128, get_pt);
simpleserial_addcmd(‘u’, 256, get_pt);

Unfortunately, things do not work as expected when I use the ‘u’ command, for 256 bytes. Your second point seems fair, I hadn’t increased the scope.adc.timeout. But even after increasing a lot this value, my problems still seem to persist:
For the 1024-bit version, I still get warnings about the timouts, but the traces still get captured (most of the time, as I sometimes get fewer points than expected errors). I get about a portion of trace (24400 points) every 2 seconds, but this goes up to 7s/it because of the traces that don’t get captured, the errors that sometimes appear, and the fact that sometimes the traces aren’t perfectly aligned when I offset them.
For the 2048-bit version, since I get traces with 2s/it at the beginning for the 1024-bit version, I suppose that even if it’s supposed to be extremely slow, it shouldn’t be that much slower, no? I tried increasing the scope.adc.timeout as you said, to 100s, but I still can’t capture any trace.

Did I do the addcmd command right? It is strange to me that it works for 1024 bit but not for 2048.
Is there something else that could be causing this issue?

Are you using SimpleSerial v1.1 or v2.1? If it’s v1.1, the max command length is 255 bytes.
In the case of SS 2.1, the max length is 250.
So you can’t send a 256-byte key over in a single command; you’ll have to split it into two commands.

That was indeed the problem, I tried sending a 256-byte key directly. Now, sending two 128-bit keys works fine (even though I still have the Timeout warnings).
Thank you for your help!