A password sent again and again is the same every time. A challenge that changes each time makes each answer good for one use only.
Car key fobs, tap-to-pay cards and building passes do not send a fixed code. The reader sends a random number, and the card answers in a way only it can. Next time the number is different.
In the XOR lesson the keypad sent the same locked PIN every time. Anyone who ever heard that number has a number that works today, tomorrow and next week, without ever knowing the key.
The fix is a challenge and response:
The secret key never goes through the air, and the answer is different whenever the challenge is.
In the code the challenge travels under the name chall, not challenge: send value names are 8 characters at most (Agreeing a key in the open), and challenge has 9.
Make your prediction first. Help opens once you've locked it in.

let secretKey = 7
let challenge = 0
function answer(n: number): number {
return (n * secretKey + 3) % 100
}
radio.setGroup(5)
input.onButtonPressed(Button.A, function () {
radio.sendString("KNOCK")
})
radio.onReceivedString(function (receivedString) {
if (receivedString == "KNOCK") {
challenge = randint(10, 99)
radio.sendValue("chall", challenge)
}
})
radio.onReceivedValue(function (name, value) {
if (name == "chall") {
radio.sendValue("answer", answer(value))
} else if (name == "answer") {
if (value == answer(challenge)) {
basic.showIcon(IconNames.Yes)
} else {
basic.showIcon(IconNames.No)
}
}
})
Press A a few times. Open Show data and compare the challenge and answer numbers each time.

let secretKey = 7
let challenge = 0
function answer(n: number): number {
return (n * secretKey + 3) % 100
}
radio.setGroup(5)
input.onButtonPressed(Button.A, function () {
radio.sendString("KNOCK")
})
radio.onReceivedString(function (receivedString) {
if (receivedString == "KNOCK") {
challenge = randint(10, 99)
radio.sendValue("chall", challenge)
}
})
radio.onReceivedValue(function (name, value) {
if (name == "chall") {
radio.sendValue("answer", answer(value))
} else if (name == "answer") {
if (value == answer(challenge)) {
basic.showIcon(IconNames.Yes)
} else {
basic.showIcon(IconNames.No)
}
}
})

let secretKey = 7
let challenge = 0
function answer(n: number): number {
return (n * secretKey + 3) % 100
}
radio.setGroup(5)
input.onButtonPressed(Button.A, function () {
radio.sendString("KNOCK")
})
radio.onReceivedString(function (receivedString) {
if (receivedString == "KNOCK") {
challenge = randint(10, 99)
radio.sendValue("chall", challenge)
}
})
radio.onReceivedValue(function (name, value) {
if (name == "chall") {
radio.sendValue("answer", answer(value))
} else if (name == "answer") {
if (value == answer(challenge)) {
basic.showIcon(IconNames.Yes)
} else {
basic.showIcon(IconNames.No)
}
}
})
The lock picks the challenge 20. What answer opens the lock? (n × 7 + 3, remainder after dividing by 100.)
For each item, does it cross the air in the challenge-and-response?
Make the lock count how many times it opened, and show the count when B is pressed.
Make a variable opened. Add one to it when the answer is right. B shows it.
The lock counts how many times it opened; B shows the count.
This ticks by itself when your blocks do what is asked.
Make the lock safer. After three wrong answers it shows a skull and ignores knocks for five seconds. Why does this help against someone who just guesses?
Add one to wrong when an answer is wrong and set wrong to 0 when it is right.
On a knock, if wrong is 3 or more: show a skull, pause 5 seconds, set wrong to 0. Otherwise send the challenge.
After three wrong answers the lock refuses to give a challenge for five seconds.
This ticks by itself when your blocks do what is asked.
Students build a challenge-and-response lock so that a heard answer cannot be used again, then add a lockout after three wrong answers. About 50 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
The idea: to prove you know a secret without saying it, the other side sets a random question, the challenge, and you answer it using the secret. A fresh challenge each time means an old answer fits only the old challenge.
Everyday picture: a bank clerk who asks for a random character of your password each time. Where it breaks: if the same question comes up, the answer works again; the challenge must be random and not repeat.
Honest limits: the answer function here, (n × key + 3) mod 100, is a toy: someone who collects enough challenges and answers can work out the key, and with only 90 possible challenges they repeat soon. Real systems use a hash function (a one-way mix) and huge challenges. Tell students the toy is for learning the shape of the idea.
Same program on both micro:bits: the simulator runs two copies. The one where A is pressed acts as the key; the other acts as the lock.
Why a fixed password fails once heard, and a fresh challenge doesn't. Ask what a listener could reuse, and whether the answer ever repeats.
Stretch: Make the challenge 3 digits and store it as a number. Why does a longer challenge repeat less often?
Support: Give the lockout in outline: students fill in the conditions.
Next: capture-the-flag puzzles, then defend a whole system.